001: package org.andromda.core.translation.library;
002:
003: import java.util.ArrayList;
004: import java.util.Collection;
005: import java.util.Iterator;
006: import java.util.LinkedHashMap;
007: import java.util.Map;
008:
009: import org.andromda.core.common.ExceptionUtils;
010: import org.andromda.core.translation.TranslationUtils;
011: import org.apache.commons.lang.StringUtils;
012: import org.apache.commons.lang.builder.ToStringBuilder;
013:
014: /**
015: * Represents a translation XML template found within a translation library.
016: *
017: * @author Chad Brandon
018: */
019: public class Translation {
020: private String name;
021: private final Map fragments = new LinkedHashMap();
022: private final Collection ignorePatterns = new ArrayList();
023: private Collection validatePatterns; // (wouter) TODO: Chad, this field is only updated, never queried, can we remove it ?
024:
025: /**
026: * The library translation to which this translation belongs.
027: */
028: private LibraryTranslation libraryTranslation;
029:
030: /**
031: * Gets the LibraryTranslation to which this Translation belongs.
032: *
033: * @return LibraryTranslation
034: */
035: protected LibraryTranslation getLibraryTranslation() {
036: final String methodName = "Translation.getLibraryTranslation";
037:
038: // should never happen, but it doesn't hurt to be safe
039: if (this .libraryTranslation == null) {
040: throw new LibraryException(methodName
041: + " - libraryTranslation can not be null");
042: }
043: return libraryTranslation;
044: }
045:
046: /**
047: * Sets the LibraryTranslation to which this Translation belongs.
048: *
049: * @param translation the LibraryTranslation to which this Translation belongs.
050: */
051: protected void setLibraryTranslation(
052: final LibraryTranslation translation) {
053: libraryTranslation = translation;
054: }
055:
056: /**
057: * Gets the fragment matching (using regular expressions) the specified name.
058: *
059: * @param name the name of the fragment to retrieve.
060: * @return Fragment
061: */
062: protected Fragment getFragment(final String name) {
063: Fragment fragment = null;
064: Iterator names = fragments.keySet().iterator();
065:
066: // search through the names and the first name that matches
067: // one of the names return the value of that name.
068: while (names.hasNext()) {
069: String nextName = (String) names.next();
070: if (name.matches(nextName)) {
071: fragment = (Fragment) fragments.get(nextName);
072: }
073: }
074:
075: // if the fragment is null, and the name isn't in an ignorePattern
076: // element, then give an error
077: if (fragment == null && !this .isIgnorePattern(name)) {
078: // TODO: make this work correctly with unsupported functions.
079:
080: /*
081: * logger.error("ERROR! expression fragment '" + name + "' is not
082: * currently supported --> add a <fragment/> with " + " a name that
083: * matches this expression to your translation file " + "'" +
084: * this.getLibraryTranslation().getFile() + "' to enable support");
085: */
086: }
087: return fragment;
088: }
089:
090: /**
091: * Adds a new Translation fragment to the Translation.
092: *
093: * @param fragment
094: */
095: public void addFragment(final Fragment fragment) {
096: ExceptionUtils.checkNull("fragment", fragment);
097: fragment.setTranslation(this );
098: this .fragments.put(fragment.getName(), fragment);
099: }
100:
101: /**
102: * Gets the name of this Translation.
103: *
104: * @return String
105: */
106: protected String getName() {
107: return name;
108: }
109:
110: /**
111: * @param name
112: */
113: protected void setName(final String name) {
114: this .name = name;
115: }
116:
117: /**
118: * Adds an <code>ignorePattern</code> to the Collection of ignorePatterns.
119: *
120: * @param ignorePattern the pattern to ignore.
121: */
122: public void addIgnorePattern(final String ignorePattern) {
123: this .ignorePatterns.add(StringUtils.trimToEmpty(ignorePattern));
124: }
125:
126: /**
127: * Adds an <code>validatePattern</code> to the Collection of validatePatterns.
128: *
129: * @param validatePattern the pattern to validate.
130: */
131: public void addValidatePattern(final String validatePattern) {
132: this .validatePatterns.add(StringUtils
133: .trimToEmpty(validatePattern));
134: }
135:
136: /**
137: * Checks to see if the pattern is an ignore pattern. What this means is that if if this pattern matches on a
138: * regular expression found in the collection of ignore patterns then the TranslationLibrary won't complain if it
139: * doesn't match a fragment name.
140: *
141: * @param pattern
142: * @return boolean <code>true</code> if its an ignore pattern, <code>false</code> otherwise.
143: */
144: public boolean isIgnorePattern(String pattern) {
145: boolean isIgnorePattern = false;
146: pattern = StringUtils.trimToEmpty(pattern);
147: Iterator ignorePatterns = this .ignorePatterns.iterator();
148:
149: // search through the ignorePatterns and see if one
150: // of them matches the passed in pattern.
151: while (ignorePatterns.hasNext()) {
152: String nextIgnorePattern = StringUtils
153: .trimToEmpty((String) ignorePatterns.next());
154: isIgnorePattern = pattern.matches(nextIgnorePattern);
155: if (isIgnorePattern) {
156: break;
157: }
158: }
159: return isIgnorePattern;
160: }
161:
162: /**
163: * Gets the "translated" value of this Fragment if it exists. That is, it retrieves the fragment body for the name
164: * of this fragment and replaces any fragment references with other fragment bodies (if they exist)
165: *
166: * @param name the name of the fragment.
167: * @param kind the kind of the fragment.
168: * @return String the translated body of the fragment kind.
169: */
170: protected String getTranslated(String name, String kind) {
171: // clean the strings first
172: name = StringUtils.trimToEmpty(name);
173: kind = StringUtils.trimToEmpty(kind);
174:
175: ExceptionUtils.checkEmpty("name", name);
176:
177: Fragment fragment = this .getFragment(name);
178: String translated = "";
179: if (fragment != null) {
180: translated = fragment.getKind(kind);
181: String begin = "fragment{";
182: int beginLength = begin.length();
183: String end = "}";
184: for (int beginIndex = translated.indexOf(begin); beginIndex != -1; beginIndex = translated
185: .indexOf(begin)) {
186: String fragmentName = translated.substring(beginIndex
187: + beginLength, translated.length());
188: int endIndex = fragmentName.indexOf(end);
189: if (endIndex != -1) {
190: fragmentName = fragmentName.substring(0, endIndex);
191: }
192: StringBuffer toReplace = new StringBuffer(begin);
193: toReplace.append(fragmentName);
194: toReplace.append(end);
195: translated = StringUtils.replace(translated, toReplace
196: .toString(), this .getTranslated(fragmentName,
197: kind));
198: }
199: }
200: return TranslationUtils.removeExtraWhitespace(translated);
201: }
202:
203: /**
204: * @see java.lang.Object#toString()
205: */
206: public String toString() {
207: return ToStringBuilder.reflectionToString(this);
208: }
209: }
|