View Javadoc

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