View Javadoc

1   package org.andromda.core.common;
2   
3   import java.io.BufferedReader;
4   import java.io.InputStream;
5   import java.io.InputStreamReader;
6   import java.io.StringWriter;
7   import java.util.Collection;
8   import java.util.Iterator;
9   import java.util.LinkedHashMap;
10  import java.util.Map;
11  
12  import org.andromda.core.configuration.NamespaceProperties;
13  import org.andromda.core.configuration.Namespaces;
14  import org.andromda.core.configuration.Property;
15  import org.andromda.core.mapping.Mapping;
16  import org.andromda.core.mapping.Mappings;
17  import org.apache.commons.lang.StringUtils;
18  
19  
20  /***
21   * <p/>
22   * A class that performs the merging abilities for the AndroMDA core. </p>
23   * <p/>
24   * Merging takes place when the {@link NamespaceProperties#MERGE_MAPPINGS_URI} is found within the
25   * <code>namespace</code> and merge mappings are used to replace any matching patterns in the given <code>string</code>.
26   * </p>
27   *
28   * @author Chad Brandon
29   */
30  public class Merger
31  {
32      /***
33       * The shared instance
34       */
35      private static final Merger instance = new Merger();
36  
37      /***
38       * Stores the cached merge mappings already found (so we don't need to reconstruct again each time).
39       */
40      private final Map mergeMappingsCache = new LinkedHashMap();
41  
42      /***
43       * Gets the shared Merger instance. Normally you'll want to retrieve the instance through this method.
44       *
45       * @return the shared instance.
46       */
47      public static Merger instance()
48      {
49          return instance;
50      }
51  
52      /***
53       * <p>
54       * Retrieves the <em>merged</em> string. The merging takes place when
55       * the {@link NamespaceProperties#MERGE_MAPPINGS_URI}is found within the
56       * <code>namespace</code> and the merge mappings are used to replace any
57       * matching patterns in the given <code>string</code>.
58       * </p>
59       *
60       * @param string the String to be replaced
61       * @param namespace This namespace is searched when attempting to find the
62       *        {@link NamespaceProperties#MERGE_MAPPINGS_URI}.
63       * @return the replaced String.
64       */
65      public String getMergedString(
66          String string,
67          final String namespace)
68      {
69          // avoid any possible infinite recursion with the mergedStringCache
70          // check (may need to refactor the mergedStringCache solution)
71          if (namespace != null && string != null)
72          {
73              final Mappings mergeMappings = this.getMergeMappings(namespace);
74              if (mergeMappings != null)
75              {
76                  final Collection mappings = mergeMappings.getMappings();
77                  if ((mappings != null) && !mappings.isEmpty())
78                  {
79                      for (final Iterator mappingsIterator = mappings.iterator(); mappingsIterator.hasNext();)
80                      {
81                          final Mapping mapping = (Mapping)mappingsIterator.next();
82                          final Collection froms = mapping.getFroms();
83  
84                          if (froms != null && !froms.isEmpty())
85                          {
86                              for (final Iterator fromsIterator = froms.iterator(); fromsIterator.hasNext();)
87                              {
88                                  final String from = StringUtils.trimToEmpty((String)fromsIterator.next());
89  
90                                  if (StringUtils.isNotEmpty(from))
91                                  {
92                                      final String to = mapping.getTo() != null ? mapping.getTo().trim() : "";
93                                      string = StringUtils.replace(string, from, to);
94                                  }
95                              }
96                          }
97                      }
98                  }
99              }
100         }
101         return string;
102     }
103 
104     /***
105      * Retrieves the <em>merged</em> string. The merging takes place when
106      * the {@link NamespaceProperties#MERGE_MAPPINGS_URI}is found within the
107      * <code>namespace</code> and the merge mappings are used to replace any
108      * matching patterns in the given <code>inputStream</code>.
109      * </p>
110      *
111      * @param inputStream the InputStream instance which is first converted
112      *        to a String and then merged.
113      * @param namespace This namespace is searched when attempting to find the
114      *        {@link NamespaceProperties#MERGE_MAPPINGS_URI}.
115      * @return the replaced String.
116      */
117     public String getMergedString(
118         final InputStream inputStream,
119         final String namespace)
120     {
121         try
122         {
123             StringWriter writer = new StringWriter();
124             BufferedReader inputReader = new BufferedReader(new InputStreamReader(inputStream));
125             for (int ctr = inputReader.read(); ctr != -1; ctr = inputReader.read())
126             {
127                 writer.write(ctr);
128             }
129             inputReader.close();
130             inputReader = null;
131             final String string = writer.toString();
132             writer.close();
133             writer = null;
134             return this.getMergedString(string, namespace);
135         }
136         catch (final Exception exception)
137         {
138             throw new MergerException(exception);
139         }
140     }
141 
142     /***
143      * Indicates whether or not the given <code>namespace</code>
144      * requires a merge.
145      * @param namespace the namespace to evaluate.
146      * @return true/false
147      */
148     public boolean requiresMerge(final String namespace)
149     {
150         final Mappings mergeMappings = this.getMergeMappings(namespace);
151         return (mergeMappings != null) && !mergeMappings.getMappings().isEmpty();
152     }
153 
154     /***
155      * Attempts to retrieve the Mappings instance for the given <code>mergeMappingsUri</code> belonging to the given
156      * <code>namespace</code>.
157      *
158      * @param namespace the namespace to which the mappings belong.
159      * @return the Mappings instance.
160      */
161     private Mappings getMergeMappings(final String namespace)
162     {
163         Mappings mergeMappings = null;
164         if (StringUtils.isNotBlank(namespace))
165         {
166             final Property mergeMappingsUri =
167                 Namespaces.instance().getProperty(namespace, NamespaceProperties.MERGE_MAPPINGS_URI, false);
168             String mergeMappingsUriValue = (mergeMappingsUri != null) ? mergeMappingsUri.getValue() : null;
169             if (StringUtils.isNotBlank(mergeMappingsUriValue))
170             {
171                 mergeMappings = (Mappings)this.mergeMappingsCache.get(mergeMappingsUriValue);
172 
173                 if (mergeMappings == null)
174                 {
175                     mergeMappings = Mappings.getInstance(mergeMappingsUriValue);
176                     this.mergeMappingsCache.put(mergeMappingsUriValue, mergeMappings);
177                 }
178             }
179         }
180         return mergeMappings;
181     }
182 }