View Javadoc

1   /**
2    * - Digitalis Internal Framework v2.0 - (C) 2007, Digitalis Informatica. Distribuicao e Gestao de Informatica, Lda.
3    * Estrada de Paco de Arcos num.9 - Piso -1 2780-666 Paco de Arcos Telefone: (351) 21 4408990 Fax: (351) 21 4408999
4    * http://www.digitalis.pt
5    */
6   package pt.digitalis.dif.dem.managers.impl;
7   
8   import java.io.File;
9   import java.io.FileInputStream;
10  import java.io.IOException;
11  import java.net.URL;
12  import java.net.URLDecoder;
13  import java.util.Enumeration;
14  import java.util.Map.Entry;
15  import java.util.Properties;
16  
17  import pt.digitalis.dif.codegen.util.DEMLoaderEntityRegistry;
18  import pt.digitalis.dif.dem.Entity;
19  import pt.digitalis.dif.dem.annotations.entities.ApplicationDefinition;
20  import pt.digitalis.dif.dem.annotations.entities.ServiceDefinition;
21  import pt.digitalis.dif.dem.interfaces.IApplication;
22  import pt.digitalis.dif.dem.interfaces.IEntity;
23  import pt.digitalis.dif.dem.interfaces.IProvider;
24  import pt.digitalis.dif.dem.interfaces.IService;
25  import pt.digitalis.dif.dem.interfaces.IStage;
26  import pt.digitalis.dif.dem.objects.messages.Message;
27  import pt.digitalis.dif.dem.objects.messages.MessageList;
28  import pt.digitalis.dif.dem.objects.messages.MessagesLocation;
29  import pt.digitalis.dif.startup.DIFGeneralConfigurationParameters;
30  import pt.digitalis.dif.startup.DIFStartupConfiguration;
31  import pt.digitalis.dif.utils.logging.DIFLogger;
32  import pt.digitalis.utils.bytecode.holders.ClassHolder;
33  import pt.digitalis.utils.inspection.ResourceUtils;
34  import pt.digitalis.utils.inspection.exception.ResourceNotFoundException;
35  
36  /**
37   * Manages the DEM messages, providing operations for access, pooling and persistence.
38   * 
39   * @author Pedro Viegas <a href="mailto:pviegas@digitalis.pt">pviegas@digitalis.pt</a>
40   * @author Rodrigo Gonçalves <a href="mailto:rgoncalves@digitalis.pt">rgoncalves@digitalis.pt</a>
41   * @created 2007/06/01
42   */
43  public class MessageManagerImpl extends AbstractMessageManager {
44  
45      /**
46       * @see pt.digitalis.dif.dem.managers.IMessageManager#collectEntityMessagesFromRepository(java.lang.Class)
47       */
48      public MessageList collectEntityMessagesFromRepository(Class<?> clazz)
49      {
50  
51          String fileName;
52          String name = clazz.getSimpleName();
53  
54          // Add the conventioned location
55          if (DIFStartupConfiguration.getMessagesLocation().equals(MessagesLocation.MESSAGES_FOLDER))
56              fileName = MESSAGES_FOLDER + clazz.getSimpleName() + AbstractMessageManager.DEFAULT_MESSAGE_FILE_EXTENSION;
57          else
58              fileName = clazz.getName().replace(".", "/") + AbstractMessageManager.DEFAULT_MESSAGE_FILE_EXTENSION;
59  
60          return readMessageFile(fileName, name);
61      }
62  
63      /**
64       * @see pt.digitalis.dif.dem.managers.IMessageManager#collectEntityMessagesFromRepository(pt.digitalis.dif.dem.Entity,
65       *      java.lang.Object)
66       */
67      public MessageList collectEntityMessagesFromRepository(Entity type, Object instance)
68      {
69  
70          // If there is no type let's treat this like any other normal class
71          if (type == null)
72              return collectEntityMessagesFromRepository(instance.getClass());
73  
74          // Otherwise let's build a logical message file location based on the DEM hierarchy
75          String messageFile;
76          String name;
77  
78          IEntity entity = (IEntity) instance;
79          name = type.toString() + " " + AbstractMessageManager.NUMBER_SIGN + entity.getID();
80  
81          if (DIFStartupConfiguration.getMessagesLocation().equals(MessagesLocation.MESSAGES_FOLDER))
82          {
83              messageFile = entity.getOriginalClassName();
84              messageFile = messageFile.substring(messageFile.lastIndexOf(".") + 1)
85                      + AbstractMessageManager.DEFAULT_MESSAGE_FILE_EXTENSION;
86  
87              if (type.equals(Entity.STAGE))
88              {
89                  IStage stage = (IStage) instance;
90  
91                  messageFile = stage.getService().getApplication().getProvider().getID() + "/"
92                          + stage.getService().getApplication().getID() + "/" + stage.getService().getID() + "/"
93                          + messageFile;
94              }
95              if (type.equals(Entity.SERVICE))
96              {
97                  IService service = (IService) instance;
98  
99                  messageFile = service.getApplication().getProvider().getID() + "/" + service.getApplication().getID()
100                         + "/" + service.getID() + "/" + messageFile;
101             }
102             if (type.equals(Entity.APPLICATION))
103             {
104                 IApplication application = (IApplication) instance;
105 
106                 messageFile = application.getProvider().getID() + "/" + application.getID() + "/" + messageFile;
107             }
108             if (type.equals(Entity.PROVIDER))
109             {
110                 IProvider provider = (IProvider) instance;
111 
112                 messageFile = provider.getID() + "/" + messageFile;
113             }
114 
115             // Add the conventioned prefix
116             messageFile = MESSAGES_FOLDER + messageFile;
117 
118         }
119         else
120         {
121             messageFile = entity.getOriginalClassName();
122             messageFile = messageFile.replace(".", "/") + AbstractMessageManager.DEFAULT_MESSAGE_FILE_EXTENSION;
123         }
124 
125         return readMessageFile(messageFile, name);
126     }
127 
128     /**
129      * @see pt.digitalis.dif.dem.managers.IMessageManager#collectEntityMessagesFromRepository(pt.digitalis.dif.dem.Entity,
130      *      java.lang.String, java.lang.String, java.lang.String)
131      */
132     public MessageList collectEntityMessagesFromRepository(Entity type, String id, String className, String parentID)
133             throws ResourceNotFoundException
134     {
135 
136         final String PROVIDER_ATTRIBUTE_NAME = "provider";
137         final String APPLICATION_ATTRIBUTE_NAME = "application";
138 
139         // Otherwise let's build a logical message file location based on the DEM hierarchy
140         String messageFile;
141         String name;
142 
143         name = type.toString() + " " + AbstractMessageManager.NUMBER_SIGN + id;
144 
145         ClassHolder classHolder = null;
146         String applicationID = null;
147         String providerID = null;
148         String serviceID = null;
149 
150         if (DIFStartupConfiguration.getMessagesLocation().equals(MessagesLocation.MESSAGES_FOLDER))
151         {
152             messageFile = className.substring(className.lastIndexOf(".") + 1);
153             messageFile += AbstractMessageManager.DEFAULT_MESSAGE_FILE_EXTENSION;
154 
155             if (type.equals(Entity.STAGE))
156             {
157 
158                 // Stage parent is a service, use the parentID (service) to find the application, which is the really
159                 // needed one
160                 classHolder = DEMLoaderEntityRegistry.getService(parentID.toLowerCase());
161                 if (classHolder != null)
162                 {
163                     serviceID = classHolder.generateID();
164                     applicationID = (classHolder.getAnnotations().get(ServiceDefinition.class.getCanonicalName())
165                             .getMembers().get(APPLICATION_ATTRIBUTE_NAME).toString()).toLowerCase();
166                     classHolder = DEMLoaderEntityRegistry.getApplication(applicationID);
167                     // Now use the application to fetch the provider
168                     providerID = (classHolder.getAnnotations().get(ApplicationDefinition.class.getCanonicalName())
169                             .getMembers().get(PROVIDER_ATTRIBUTE_NAME).toString()).toLowerCase();
170 
171                     // id is stageID, parentID is service ID
172                     messageFile = providerID + "/" + applicationID + "/" + serviceID + "/" + id + "/" + messageFile;
173                 }
174             }
175             else if (type.equals(Entity.SERVICE))
176             {
177 
178                 // Service parent is an application
179                 classHolder = DEMLoaderEntityRegistry.getApplication(parentID.toLowerCase());
180 
181                 if (classHolder != null)
182                 {
183                     applicationID = classHolder.generateID();
184                     // Now use the application to fetch the provider
185                     providerID = classHolder.getAnnotations().get(ApplicationDefinition.class.getCanonicalName())
186                             .getMembers().get(PROVIDER_ATTRIBUTE_NAME).toString();
187                     classHolder = DEMLoaderEntityRegistry.getProvider(providerID.toLowerCase());
188                     providerID = classHolder.generateID();
189 
190                     // id is serviceID
191                     messageFile = providerID + "/" + parentID.toLowerCase() + "/" + id + "/" + messageFile;
192                 }
193 
194                 messageFile = parentID.toLowerCase() + "/" + id + "/" + messageFile;
195             }
196             else if (type.equals(Entity.PROVIDER))
197             {
198                 messageFile = id + "/" + messageFile;
199             }
200 
201             // Add the conventioned prefix
202             messageFile = MESSAGES_FOLDER + messageFile;
203 
204         }
205         else
206         {
207             messageFile = className;
208             messageFile = messageFile.replace(".", "/") + AbstractMessageManager.DEFAULT_MESSAGE_FILE_EXTENSION;
209         }
210 
211         if (classHolder != null || !(type.equals(Entity.SERVICE) || type.equals(Entity.STAGE)))
212             return readMessageFile(messageFile, name);
213         else
214             return null;
215     }
216 
217     /**
218      * @see pt.digitalis.dif.dem.managers.IMessageManager#collectEntityMessagesFromRepository(java.lang.String)
219      */
220     public MessageList collectEntityMessagesFromRepository(String messagePath)
221     {
222 
223         String fileName;
224 
225         // Add the conventioned location
226         if (DIFStartupConfiguration.getMessagesLocation().equals(MessagesLocation.MESSAGES_FOLDER))
227             fileName = MESSAGES_FOLDER + messagePath + AbstractMessageManager.DEFAULT_MESSAGE_FILE_EXTENSION;
228         else
229             fileName = messagePath.replace(".", "/") + AbstractMessageManager.DEFAULT_MESSAGE_FILE_EXTENSION;
230 
231         return readMessageFile(fileName, messagePath);
232     }
233 
234     /**
235      * @see pt.digitalis.dif.dem.managers.IMessageManager#isPersistent()
236      */
237     public boolean isPersistent()
238     {
239         return false;
240     }
241 
242     /**
243      * Does the actual reading of the resource file
244      * 
245      * @param fileName
246      *            the name of the message resource file to read
247      * @param entityName
248      *            the name of the entity to witch we are loading the messages
249      * @return the read messages
250      */
251     protected MessageList readMessageFile(String fileName, String entityName)
252     {
253 
254         MessageList messages = new MessageList();
255         boolean error = false;
256         String fileNameBaseDir;
257 
258         fileName = fileName.replace('/', File.separatorChar);
259 
260         if (fileName.lastIndexOf(File.separatorChar) == -1)
261             error = true;
262 
263         // If there are files to process...
264         if (!error)
265         {
266             fileNameBaseDir = fileName.substring(0, fileName.lastIndexOf(File.separator));
267 
268             try
269             {
270                 Properties messageFileProps = new Properties();
271                 String language = null;
272 
273                 // Get the URLs for the message files based on the default "xxx.message"
274                 Enumeration<URL> messageFileDirs = Thread.currentThread().getContextClassLoader()
275                         .getResources(fileNameBaseDir);
276 
277                 // For each file...
278                 while (messageFileDirs.hasMoreElements())
279                 {
280                     URL messageDir = messageFileDirs.nextElement();
281 
282                     try
283                     {
284                         for (String messageFileName: ResourceUtils.getFilesInDir(messageDir))
285                         {
286 
287                             String messageFullFileName;
288                             boolean isCorrectFile = true;
289 
290                             if (messageDir.getProtocol().equalsIgnoreCase("FILE"))
291                             {
292                                 messageFullFileName = fileNameBaseDir + File.separator + messageFileName;
293                                 isCorrectFile = messageFullFileName.contains(fileName);
294 
295                             }
296                             else
297                             {
298                                 messageFullFileName = messageFileName;
299                                 isCorrectFile = messageFullFileName.contains(fileName.replaceAll("\\\\", "/"));
300                             }
301 
302                             // If the file is for the current class. Many files will exist on the given directory
303                             if (isCorrectFile)
304                             {
305                                 if (DIFStartupConfiguration.getDeveloperMode()
306                                         && messageDir.getProtocol().equalsIgnoreCase("FILE"))
307                                 {
308                                     String filePath = messageDir.getPath();
309 
310                                     if (!filePath.endsWith(File.separator))
311                                         filePath += File.separator;
312 
313                                     filePath += messageFileName;
314 
315                                     messageFileProps.load(new FileInputStream(new File(URLDecoder.decode(filePath,
316                                             "UTF-8"))));
317 
318                                 }
319                                 else
320                                     // ...load the messages to the 'properties' object...
321                                     messageFileProps.load(Thread.currentThread().getContextClassLoader()
322                                             .getResourceAsStream(messageFullFileName));
323 
324                                 // Infer the language from the file name
325                                 language = messageFileName.substring(messageFileName.lastIndexOf(".")).toLowerCase();
326 
327                                 // Process the language (check if it's the default)
328                                 if (AbstractMessageManager.DEFAULT_MESSAGE_FILE_EXTENSION.equals(language))
329                                     language = DIFGeneralConfigurationParameters.getInstance().getDefaultLanguage();
330                                 else
331                                 {
332                                     language = language.substring(1);
333                                     addSupportedLanguage(language);
334                                 }
335 
336                                 // For each entry on the 'properties'....
337                                 for (Entry<Object, Object> entry: messageFileProps.entrySet())
338                                 {
339                                     // ...add it as a message translation
340                                     messages.addMessageTranslation(entry.getKey().toString().toLowerCase(), language,
341                                             new Message(entry.getValue().toString()));
342                                 }
343                                 messageFileProps = new Properties();
344                             }
345                         }
346 
347                     }
348                     catch (ResourceNotFoundException e)
349                     {
350                         error = true;
351                     }
352                 }
353 
354             }
355             catch (IOException e)
356             {
357                 /*
358                  * Untestable in the sense that one can't have a way to explicitly raise an IOException due to
359                  * InputStream errors.
360                  */
361                 error = true;
362             }
363         }
364 
365         // Inform the user about message processing
366         if (error)
367             DIFLogger.getLogger().debug(entityName + ": No message file present.");
368         else
369             DIFLogger.getLogger().debug(entityName + ": message file " + fileName + " loaded");
370 
371         // Return the message list (might be empty!!)
372         return messages;
373     }
374 }