1 package org.andromda.core.translation.library;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.LinkedHashMap;
6 import java.util.Map;
7 import org.andromda.core.common.ExceptionUtils;
8 import org.andromda.core.translation.TranslationUtils;
9 import org.apache.commons.lang.StringUtils;
10 import org.apache.commons.lang.builder.ToStringBuilder;
11
12 /**
13 * Represents a translation XML template found within a translation library.
14 *
15 * @author Chad Brandon
16 */
17 public class Translation
18 {
19 private String name;
20 private final Map<String, Fragment> fragments = new LinkedHashMap<String, Fragment>();
21 private final Collection<String> ignorePatterns = new ArrayList<String>();
22
23 /**
24 * The library translation to which this translation belongs.
25 */
26 private LibraryTranslation libraryTranslation;
27
28 /**
29 * Gets the LibraryTranslation to which this Translation belongs.
30 *
31 * @return LibraryTranslation
32 */
33 protected LibraryTranslation getLibraryTranslation()
34 {
35 // should never happen, but it doesn't hurt to be safe
36 if (this.libraryTranslation == null)
37 {
38 throw new LibraryException("Translation.getLibraryTranslation - libraryTranslation can not be null");
39 }
40 return libraryTranslation;
41 }
42
43 /**
44 * Sets the LibraryTranslation to which this Translation belongs.
45 *
46 * @param translation the LibraryTranslation to which this Translation belongs.
47 */
48 protected void setLibraryTranslation(final LibraryTranslation translation)
49 {
50 libraryTranslation = translation;
51 }
52
53 /**
54 * Gets the fragment matching (using regular expressions) the specified name.
55 *
56 * @param name the name of the fragment to retrieve.
57 * @return Fragment
58 */
59 protected Fragment getFragment(final String name)
60 {
61 Fragment fragment = null;
62 // search through the names and the first name that matches
63 // one of the names return the value of that name.
64 for (String nextName : fragments.keySet())
65 {
66 if (name.matches(nextName))
67 {
68 fragment = fragments.get(nextName);
69 }
70 }
71
72 // if the fragment is null, and the name isn't in an ignorePattern
73 // element, then give an error
74 if (fragment == null && !this.isIgnorePattern(name))
75 {
76 // TODO: make this work correctly with unsupported functions.
77
78 /*
79 * logger.error("ERROR! expression fragment '" + name + "' is not
80 * currently supported --> add a <fragment/> with " + " a name that
81 * matches this expression to your translation file " + "'" +
82 * this.getLibraryTranslation().getFile() + "' to enable support");
83 */
84 }
85 return fragment;
86 }
87
88 /**
89 * Adds a new Translation fragment to the Translation.
90 *
91 * @param fragment new Translation fragment
92 */
93 public void addFragment(final Fragment fragment)
94 {
95 ExceptionUtils.checkNull(
96 "fragment",
97 fragment);
98 fragment.setTranslation(this);
99 this.fragments.put(
100 fragment.getName(),
101 fragment);
102 }
103
104 /**
105 * Gets the name of this Translation.
106 *
107 * @return String
108 */
109 protected String getName()
110 {
111 return name;
112 }
113
114 /**
115 * @param name
116 */
117 protected void setName(final String name)
118 {
119 this.name = name;
120 }
121
122 /**
123 * Adds an <code>ignorePattern</code> to the Collection of ignorePatterns.
124 *
125 * @param ignorePattern the pattern to ignore.
126 */
127 public void addIgnorePattern(final String ignorePattern)
128 {
129 this.ignorePatterns.add(StringUtils.trimToEmpty(ignorePattern));
130 }
131
132 /**
133 * Checks to see if the pattern is an ignore pattern. What this means is that if if this pattern matches on a
134 * regular expression found in the collection of ignore patterns then the TranslationLibrary won't complain if it
135 * doesn't match a fragment name.
136 *
137 * @param pattern
138 * @return boolean <code>true</code> if its an ignore pattern, <code>false</code> otherwise.
139 */
140 public boolean isIgnorePattern(String pattern)
141 {
142 boolean isIgnorePattern = false;
143 pattern = StringUtils.trimToEmpty(pattern);
144 // search through the ignorePatterns and see if one
145 // of them matches the passed in pattern.
146 for (String nextIgnorePattern : this.ignorePatterns)
147 {
148 isIgnorePattern = pattern.matches(StringUtils.trimToEmpty(nextIgnorePattern));
149 if (isIgnorePattern)
150 {
151 break;
152 }
153 }
154 return isIgnorePattern;
155 }
156
157 /**
158 * Gets the "translated" value of this Fragment if it exists. That is, it retrieves the fragment body for the name
159 * of this fragment and replaces any fragment references with other fragment bodies (if they exist)
160 *
161 * @param name the name of the fragment.
162 * @param kind the kind of the fragment.
163 * @return String the translated body of the fragment kind.
164 */
165 protected String getTranslated(
166 String name,
167 String kind)
168 {
169 // clean the strings first
170 name = StringUtils.trimToEmpty(name);
171 kind = StringUtils.trimToEmpty(kind);
172
173 ExceptionUtils.checkEmpty(
174 "name",
175 name);
176
177 Fragment fragment = this.getFragment(name);
178 String translated = "";
179 if (fragment != null)
180 {
181 translated = fragment.getKind(kind);
182 String begin = "fragment{";
183 int beginLength = begin.length();
184 String end = "}";
185 for (int beginIndex = translated.indexOf(begin); beginIndex != -1;
186 beginIndex = translated.indexOf(begin))
187 {
188 String fragmentName = translated.substring(
189 beginIndex + beginLength,
190 translated.length());
191 int endIndex = fragmentName.indexOf(end);
192 if (endIndex != -1)
193 {
194 fragmentName = fragmentName.substring(
195 0,
196 endIndex);
197 }
198 StringBuilder toReplace = new StringBuilder(begin);
199 toReplace.append(fragmentName);
200 toReplace.append(end);
201 translated =
202 StringUtils.replace(
203 translated,
204 toReplace.toString(),
205 this.getTranslated(
206 fragmentName,
207 kind));
208 }
209 }
210 return TranslationUtils.removeExtraWhitespace(translated);
211 }
212
213 /**
214 * @see Object#toString()
215 */
216 public String toString()
217 {
218 return ToStringBuilder.reflectionToString(this);
219 }
220 }