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
70
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 }