View Javadoc

1   package com.sourceforge.jpatterns.utils;
2   
3   import com.sourceforge.jpatterns.core.JPConstants;
4   import com.sourceforge.jpatterns.core.JPException;
5   import com.sourceforge.jpatterns.core.configuration.exceptions.JPConfigException;
6   import com.sourceforge.jpatterns.core.configuration.exceptions.JPInitializationException;
7   import com.sourceforge.jpatterns.core.configuration.model.JPatternsConfigBaseBean;
8   import com.sourceforge.jpatterns.schema.CastorGroupTypeItem;
9   import com.sourceforge.jpatterns.schema.CastorNameScopePriorityType;
10  import com.sourceforge.jpatterns.schema.CastorSectionType;
11  import com.sourceforge.jpatterns.schema.Config;
12  import com.sourceforge.jpatterns.schema.Factory;
13  import com.sourceforge.jpatterns.schema.JPatternsConfig;
14  import com.sourceforge.jpatterns.schema.JPatternsConfigItem;
15  import com.zmicer.utils.InputArgumentUtils;
16  import com.zmicer.utils.LoggingUtils;
17  import com.zmicer.utils.ReflexionUtils;
18  import com.zmicer.utils.StringUtils;
19  import org.apache.log4j.Logger;
20  import org.exolab.castor.xml.Unmarshaller;
21  
22  import java.io.File;
23  import java.io.FileReader;
24  import java.lang.reflect.Method;
25  import java.util.ArrayList;
26  import java.util.Arrays;
27  import java.util.List;
28  
29  /**
30   * This class contains the castor utils related to the JPatterns project (appropriate project specific model is used here).
31   * <p/>
32   * $Author:: zmicer             $<br/>
33   * $Rev:: 67                    $<br/> * $Date:: 2007-08-28 21:37:07 #$<br/>
34   */
35  public class CastorUtils
36  {
37      /**
38       * Logger instance.
39       */
40      final public static Logger LOG = Logger.getLogger(CastorUtils.class);
41  
42      /**
43       * Base name of the class to be used.
44       */
45      final protected static String GROUP_ITEM_CLASS_NAME = CastorGroupTypeItem.class.getName();
46  
47      /**
48       * Get <code>JPatternsConfig</code> using the provided file.
49       *
50       * @param file File using which we need to obtain <code>JPatternsConfig</code>
51       *             Can not be null (otherwise <code>IllegalArgumentException</code> would appear), also should point to the existed file
52       *             (otherwise <code>IllegalArgumentException</code> would appear).
53       *
54       * @return the castor object, <code>JPatternsConfig</code>. In the case of the failure it returns <code>null</null>
55       *         $Rev:: 67                    $<br/> * $Date:: 2007-08-28 21:37:07 #$<br/>
56       */
57      public static JPatternsConfig getJPatternsConfig(final File file)
58      {
59          InputArgumentUtils.checkObjects(file);
60          if (!file.isFile())
61          {
62              throw new IllegalArgumentException("The provided object is not file.");
63          }
64          try
65          {
66              FileReader fileReader = new FileReader(file);
67              Unmarshaller unmarshaller = new Unmarshaller(JPatternsConfig.class);
68              Object object = unmarshaller.unmarshal(fileReader);
69              if (null == object)
70              {
71                  final String message = "Can not instantiate the object using unmarshal operation.";
72                  LOG.debug(message);
73                  throw new IllegalStateException(message);
74              }
75              if (!(object instanceof JPatternsConfig))
76              {
77                  final String message = "The object instantiated using operation unmarshal should be the type JPatternsConfig.";
78                  LOG.debug(message);
79                  throw new IllegalStateException(message);
80              }
81              return (JPatternsConfig) object;
82          }
83          catch (Exception e)
84          {
85              LoggingUtils.logException(LOG, e, null, null);
86              throw new JPInitializationException(e);
87          }
88      }
89  
90      /**
91       * Stores and retrive all the objects of CastorSectionType (it means all the objects of this type and also child of this type).
92       * This would be performed trough the reflexion. This method is necessary because it doesn could be used without any changes in
93       * the case some new types - childs of CastorSectionType would be added - so we won't need to change the sources.
94       *
95       * @param config JPatternsConfig object to be parsed. Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
96       *
97       * @return List of <code>CastorSectionType</code> objects, could be empty List returned in the case the provided config doesn't store
98       *         the necessary objects
99       *         $Rev:: 67                    $<br/> * $Date:: 2007-08-28 21:37:07 #$<br/>
100      */
101     public static List<CastorSectionType> extractCastorSectionTypeObjects(final JPatternsConfig config)
102     {
103         InputArgumentUtils.checkObjects(config);
104 
105         final List<CastorSectionType> result = new ArrayList<CastorSectionType>();
106         final JPatternsConfigItem[] configItems = config.getJPatternsConfigItem();
107 
108         // no information
109         if (configItems.length == 0)
110         {
111             return result;
112         }
113         final JPatternsConfigItem configItem = new JPatternsConfigItem();
114         // 00: obtain the methods and find the methods the names of which start with "get" and return object of CastorSectionType
115         final String methodPrefix = "get";
116         final Method[] methods = configItem.getClass().getMethods();
117         final List<Method> methodsWeNeed = new ArrayList<Method>();
118         for (final Method method : methods)
119         {
120             final Class returnedType = method.getReturnType();
121             //  && returnedType.isArray() - earlier this method checked if array is returned
122             if (method.getName().contains(methodPrefix) && !method.getName().contains("getClass"))
123             {
124                 //final String arrayMembersClassName = ReflexionUtils.getClassNameOfArrayMembers(returnedType);
125                 // commented still could be used later
126                 try
127                 {
128                     final Object objectToCheck = returnedType.newInstance();
129                     if (objectToCheck instanceof CastorSectionType)
130                     {
131                         methodsWeNeed.add(method);
132                     }
133                 }
134                 catch (Exception e)
135                 {
136                     // just log and continue with finding the methods we need.
137                     LoggingUtils.logException(LOG, e, null, null);
138                 }
139             }
140         }
141 
142         // 01: iterate through the methods we have obtained, call them on the provided castor object, using the reflexion and accumulate
143         // the results to the result storage. Check the results of the method are the thing we need.
144         for (final JPatternsConfigItem item : configItems)
145         {
146             for (final Method method : methodsWeNeed)
147             {
148                 try
149                 {
150                     final Object object = method.invoke(item);
151                     // if (object instanceof CastorSectionType[]) was earlier
152                     if (object instanceof CastorSectionType)
153                     {
154                         result.add((CastorSectionType) object);
155                     }
156                 }
157                 catch (Exception ex)
158                 {
159                     LoggingUtils.logException(LOG, ex, null, null);
160                 }
161             }
162         }
163         return result;
164     }
165 
166     /**
167      * Extract all the possible CastorNameScopePriorityType castor objects from the provided CastorSectionType. The sense of this method is
168      * as follows: CastorSectionType is a base "sections" object and has lots of child with the business items which are the instances of
169      * the class CastorNameScopePriorityType. In the case of CastorFactoryType, CastorConfigType it would be just method getItem returning
170      * Item[] which are instances of CastorNameScopePriorityType too. But for the castorGroupType it is the method getCastorGroupTypeItem
171      * returning CastorGroupTypeItem[] each of them is a choice - in this case we would call "getChoiceValue" method.
172      *
173      * @param sectionType the section type to be analyzed. Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
174      *
175      * @return the List of the <code>CastorNameScopePriorityType</code> objects.
176      *         $Rev:: 67                    $<br/> * $Date:: 2007-08-28 21:37:07 #$<br/>
177      */
178     public static List<CastorNameScopePriorityType> extractCastorNameScopePriorityTypeObjects(final CastorSectionType sectionType)
179     {
180         InputArgumentUtils.checkObjects(sectionType);
181         final String methodPrefix = "get";
182         final String choiceValueMethod = "getChoiceValue";
183         final String groupItemName = "";
184 
185         final Method[] methods = sectionType.getClass().getMethods();
186         final List<Method> methodsWeNeed = new ArrayList<Method>();
187         for (final Method method : methods)
188         {
189             final Class returnedType = method.getReturnType();
190             if (method.getName().contains(methodPrefix) && returnedType.isArray())
191             {
192                 final String arrayMembersClassName = ReflexionUtils.getClassNameOfArrayMembers(returnedType);
193                 try
194                 {
195                     // todo [zmicer]: not sure if we need the reflexion here - may be string contains method would be enough?
196                     final Object objectToCheck = sectionType.getClass().getClassLoader().loadClass(arrayMembersClassName).newInstance();
197                     if (objectToCheck instanceof CastorNameScopePriorityType || objectToCheck instanceof CastorGroupTypeItem)
198                     {
199                         methodsWeNeed.add(method);
200                     }
201                 }
202                 catch (Exception e)
203                 {
204                     // just log and continue with finding the methods we need.
205                     LoggingUtils.logException(LOG, e, null, null);
206                 }
207             }
208         }
209 
210         // 01: iterate through the methods we have obtained, call them on the provided castor object, using the reflexion and accumulate
211         // the results to the result storage. Check the results of the method are the thing we need.
212         final List<CastorNameScopePriorityType> result = new ArrayList<CastorNameScopePriorityType>();
213         for (final Method method : methodsWeNeed)
214         {
215             try
216             {
217                 final Object object = method.invoke(sectionType);
218                 // if (object instanceof CastorSectionType[]) was earlier
219                 if (null != object)
220                 {
221                     if (object instanceof CastorNameScopePriorityType[])
222                     {
223                         result.addAll(Arrays.asList((CastorNameScopePriorityType[]) object));
224                     }
225                     else if (object instanceof CastorGroupTypeItem[])
226                     {
227                         CastorGroupTypeItem[] groupItems = (CastorGroupTypeItem[]) object;
228                         for (CastorGroupTypeItem groupItem : groupItems)
229                         {
230                             if (groupItem.getChoiceValue() instanceof CastorNameScopePriorityType)
231                             {
232                                 result.add((CastorNameScopePriorityType) groupItem.getChoiceValue());
233                             }
234                         }
235                     }
236                 }
237             }
238             catch (Exception ex)
239             {
240                 LoggingUtils.logException(LOG, ex, null, null);
241             }
242         }
243         return result;
244     }
245 
246     /**
247      * Make the scopes of all the elements here normalized. Currently (possibly smth. could be changed) it means:
248      * <br/>
249      * 1. the scopes of the root/child elements can be different
250      * 2. in the case "business" item is defined with scope and parent without - the defined scope would have power on the business item
251      * 3. in the case the parent elements is defined with a scope, then all the childs of it would be of the appropriate scope
252      * <br/>
253      * The default scope is mentioned is either the default scope of the castor root config or
254      * <code>com.sourceforge.jpatterns.core.JPConstants.DEFAULT_SCOPE_NAME</code>
255      * <br/>
256      * note1 [zmicer]: think over the adjustment of principles of normalization, as some new types could appear here, and this method would
257      * be extended (new scope supported types different from the base type CastorSectionType would appear).
258      * note2 [zmicer]: earlier at this method we retrict the case when parent and child have different scopes - for now it is allowed (it
259      * was decided to allow the support of scopes of the business item elements inside the section - it is one more scope visibility area).
260      *
261      * @param config castor root config objects to be processed.
262      *               Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
263      *
264      * @version 1.1
265      */
266     public static void validateAndNormalizeScopesPriorities(final JPatternsConfig config)
267     {
268         InputArgumentUtils.checkObjects(config);
269 
270         final boolean configHasDefaultScope = (null != config.getDefaultScope() && !"".equals(config.getDefaultScope()));
271         // 00: default scope
272         final String defaultScope = (configHasDefaultScope) ? config.getDefaultScope() :
273             com.sourceforge.jpatterns.core.JPConstants.DEFAULT_SCOPE_NAME;
274 
275         if (!configHasDefaultScope)
276         {
277             config.setDefaultScope(defaultScope);
278         }
279 
280         // 01: working with sections
281         final List<CastorSectionType> castorSectionTypes = CastorUtils.extractCastorSectionTypeObjects(config);
282         for (final CastorSectionType castorSectionType : castorSectionTypes)
283         {
284             if (null == castorSectionType.getScope() || "".equals(castorSectionType.getScope()))
285             {
286                 castorSectionType.setScope(defaultScope);
287             }
288             setValidatePriority(castorSectionType, false);
289 
290             // 02: working with items
291             final List<CastorNameScopePriorityType> items = extractCastorNameScopePriorityTypeObjects(castorSectionType);
292             for (final CastorNameScopePriorityType item : items)
293             {
294                 // 02:a - set the scope of the parent
295                 if (null == item.getScope() || "".equals(item.getScope()))
296                 {
297                     item.setScope(castorSectionType.getScope());
298                 }
299                 setValidatePriority(item, false);
300             }
301         }
302     }
303 
304     /**
305      * All the items of the provided <code>JPatternsConfig</code> - sections, business items - are made prioritized. For this
306      * <code>com.sourceforge.jpatterns.core.JPConstants.PRIORITIZED_PRIOTITY_PREFIX</code> would be added as the prefix to all the
307      * priorities. Then later, during the prioritized merging this items would have priority over the identical, but without this prefix.
308      * <br/>
309      * This functionality is introduced to make the algorithm of simlple merging of JPatterns configuration files identical with the
310      * merging with priority (when some configuration takes the priority).
311      *
312      * @param castorConfig the target JPatternsConfig root castor object objects of which should be modified (their priorities)
313      *                     Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
314      *                     $Rev:: 67                    $<br/> * $Date:: 2007-08-28 21:37:07 #$<br/>
315      */
316     public static void makePrioritized(final JPatternsConfig castorConfig)
317     {
318         InputArgumentUtils.checkObjects(castorConfig);
319         // 01: working with sections
320         final List<CastorSectionType> castorSectionTypes = CastorUtils.extractCastorSectionTypeObjects(castorConfig);
321         for (final CastorSectionType castorSectionType : castorSectionTypes)
322         {
323             setValidatePriority(castorSectionType, true);
324 
325             // 02: working with items
326             final List<CastorNameScopePriorityType> items = extractCastorNameScopePriorityTypeObjects(castorSectionType);
327             for (final CastorNameScopePriorityType item : items)
328             {
329                 setValidatePriority(item, true);
330             }
331         }
332     }
333 
334     /**
335      * Make prioritized the provided bean.
336      *
337      * @param bean the instance to be prioritized.
338      *             $Rev:: 67                    $<br/> * $Date:: 2007-08-28 21:37:07 #$<br/>
339      */
340     public static void makePrioritized(final JPatternsConfigBaseBean bean)
341     {
342         InputArgumentUtils.checkObjects(bean);
343         // 01: working with sections
344         final List<CastorSectionType> castorSectionTypes = bean.getListOfSectionItems();
345         for (final CastorSectionType castorSectionType : castorSectionTypes)
346         {
347             setValidatePriority(castorSectionType, true);
348 
349             // 02: working with items
350             final List<CastorNameScopePriorityType> items = extractCastorNameScopePriorityTypeObjects(castorSectionType);
351             for (final CastorNameScopePriorityType item : items)
352             {
353                 setValidatePriority(item, true);
354             }
355         }
356     }
357 
358     /**
359      * Set new / validate (is any) the priority field of the given castor object.
360      *
361      * @param castor          CastorNameScopePriorityType instance. Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
362      * @param makePrioritized signs if we need to make the priority prioritized (using JPConstants.PRIORITIZED_PRIOTITY_PREFIX)
363      *                        $Rev:: 67                    $<br/> * $Date:: 2007-08-28 21:37:07 #$<br/>
364      */
365     protected static void setValidatePriority(final CastorNameScopePriorityType castor, final boolean makePrioritized)
366     {
367         InputArgumentUtils.checkObjects(castor);
368         if (null == castor.getPriority() || "".equals(castor.getPriority()))
369         {
370             castor.setPriority(String.valueOf(JPConstants.DEFAULT_PRIORITY));
371         }
372         // check if it is already prioritized.
373         if (!castor.getPriority().contains(JPConstants.PRIORITIZED_PRIOTITY_PREFIX))
374         {
375             if (null == StringUtils.getInteger(castor.getPriority()))
376             {
377                 throw new JPConfigException("The following priority " + castor.getPriority() + " is incorrect.");
378             }
379             if (makePrioritized)
380             {
381                 castor.setPriority(JPConstants.PRIORITIZED_PRIOTITY_PREFIX + castor.getPriority());
382             }
383         }
384     }
385 
386     /**
387      * Get the int representation of the priority.
388      *
389      * @param castor castor object storing the priority to be used.
390      *               Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
391      *
392      * @return the int representaotion
393      *         $Rev:: 67                    $<br/> * $Date:: 2007-08-28 21:37:07 #$<br/>
394      */
395     public static int getPriority(final CastorNameScopePriorityType castor)
396     {
397         InputArgumentUtils.checkObjects(castor);
398         InputArgumentUtils.checkStrings(true, castor.getPriority());
399         String workingStr = null;
400         if (castor.getPriority().startsWith(JPConstants.PRIORITIZED_PRIOTITY_PREFIX))
401         {
402             workingStr = castor.getPriority().substring(JPConstants.PRIORITIZED_PRIOTITY_PREFIX.length());
403         }
404         else
405         {
406             workingStr = castor.getPriority();
407         }
408         final Integer integer = StringUtils.getInteger(workingStr);
409         if (null == integer)
410         {
411             throw new IllegalArgumentException("Invalid priority is set to the castor [" + castor.getPriority() + "]");
412         }
413         return integer;
414     }
415 
416     /**
417      * Get the List of <code>Config</code> castor objects by the root JPatterns configuration object. It is necessary for the convinient
418      * opering with the Config object.
419      *
420      * @param config the <code>JPatternsConfig</code> root castor config objects,
421      *               Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
422      *
423      * @return the List of the Config castor object we need, the empty List is returned in the case there are not Config objects.
424      *         $Rev:: 67                    $<br/> * $Date:: 2007-08-28 21:37:07 #$<br/>
425      */
426     public static List<Config> getConfig(final JPatternsConfig config)
427     {
428         InputArgumentUtils.checkObjects(config);
429         final List<Config> result = new ArrayList<Config>();
430         for (JPatternsConfigItem configItem : config.getJPatternsConfigItem())
431         {
432             if (null != configItem.getConfig())
433             {
434                 result.add(configItem.getConfig());
435             }
436         }
437         return result;
438     }
439 
440     /**
441      * Get the List of <code>Factory</code> castor objects by the root JPatterns configuration object. It is necessary for the convinient
442      * opering with the Factory object.
443      *
444      * @param config the <code>JPatternsConfig</code> root castor config objects,
445      *               Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
446      *
447      * @return the List of the Factory castor object we need, the empty List is returned in the case there are not Config objects.
448      *         $Rev:: 67                    $<br/> * $Date:: 2007-08-28 21:37:07 #$<br/>
449      */
450     public static List<Factory> getFactory(final JPatternsConfig config)
451     {
452         InputArgumentUtils.checkObjects(config);
453         final List<Factory> result = new ArrayList<Factory>();
454         for (JPatternsConfigItem configItem : config.getJPatternsConfigItem())
455         {
456             if (null != configItem.getFactory())
457             {
458                 result.add(configItem.getFactory());
459             }
460         }
461         return result;
462     }
463 
464     /**
465      * Add the instance of <code>Config</code> type to the provided JPatternsConfig root config object
466      *
467      * @param config     JPatternsConfig, Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
468      * @param configItem Config castor object. Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
469      *                   $Rev:: 67                    $<br/> * $Date:: 2007-08-28 21:37:07 #$<br/>
470      */
471     public static void addConfig(final JPatternsConfig config, final Config configItem)
472     {
473         InputArgumentUtils.checkObjects(config, configItem);
474         JPatternsConfigItem item = new JPatternsConfigItem();
475         item.setConfig(configItem);
476         config.addJPatternsConfigItem(item);
477     }
478 
479     /**
480      * Add the instance of <code>Config</code> type to the provided JPatternsConfig root config object
481      *
482      * @param config      JPatternsConfig, Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
483      * @param factoryItem Factory castor object. Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
484      *                    $Rev:: 67                    $<br/> * $Date:: 2007-08-28 21:37:07 #$<br/>
485      */
486     public static void addFactory(final JPatternsConfig config, final Factory factoryItem)
487     {
488         InputArgumentUtils.checkObjects(config, factoryItem);
489         JPatternsConfigItem item = new JPatternsConfigItem();
490         item.setFactory(factoryItem);
491         config.addJPatternsConfigItem(item);
492     }
493 
494     /**
495      * Construct the CastorGroupTypeItem (choice object) using the provided Object.
496      *
497      * @param object CastorNameScopePriorityType instance, can not be null, CastorGroupTypeItem should have appropriate method
498      *               set***, where *** - the base name of the provided object. Otherwise IllegalArgumentException would appeared
499      *
500      * @return the constructed CastorGroupTypeItem
501      *         $Rev:: 67                    $<br/> * $Date:: 2007-08-28 21:37:07 #$<br/>
502      */
503     public static CastorGroupTypeItem constructGroupItem(final CastorNameScopePriorityType object)
504     {
505         InputArgumentUtils.checkObjects(object);
506         final String typeToBeAdded = ReflexionUtils.getBaseName(object.getClass());
507         final Method[] methods = CastorGroupTypeItem.class.getMethods();
508         for (final Method method : methods)
509         {
510             if (method.getName().equals("set" + typeToBeAdded))
511             {
512                 try
513                 {
514                     CastorGroupTypeItem groupItem = new CastorGroupTypeItem();
515                     method.invoke(groupItem, object);
516                     return groupItem;
517                 }
518                 catch (Exception ex)
519                 {
520                     LoggingUtils.logException(LOG, ex, "Can not instantiate CastorGroupTypeItem", null);
521                     throw new JPException("Can not instantiate CastorGroupTypeItem", ex);
522                 }
523             }
524         }
525         return null;
526     }
527 
528     /**
529      * Get the String representation of the Item in the format we need (the full path would be provided).
530      * note [zmicer]: be noticed the both name and scope values should be filled for these object passed here
531      *
532      * @param section the Section object for which we need to get the full representation in the format we need
533      *                Could be null, in this case information about the section is displayed
534      * @param item    Item castor object. Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
535      *                Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
536      *
537      * @return the String representation we could use later.
538      */
539     public static String toString(final CastorSectionType section, final CastorNameScopePriorityType item)
540     {
541         InputArgumentUtils.checkObjects(item);
542         InputArgumentUtils.checkStrings(true, item.getScope(), item.getName());
543         String result = "";
544         if (null != section)
545         {
546             InputArgumentUtils.checkStrings(true, section.getScope(), section.getName());
547             result += "Section: scope [" + section.getScope() + "], name [" + section.getName() + "];";
548         }
549         return result += "Item: scope [" + item.getScope() + "], name [" + item.getName() + "];";
550     }
551 }