001package org.andromda.core.translation.library; 002 003import java.util.ArrayList; 004import java.util.Collection; 005import java.util.LinkedHashMap; 006import java.util.Map; 007import org.andromda.core.common.ExceptionUtils; 008import org.andromda.core.translation.TranslationUtils; 009import org.apache.commons.lang.StringUtils; 010import org.apache.commons.lang.builder.ToStringBuilder; 011 012/** 013 * Represents a translation XML template found within a translation library. 014 * 015 * @author Chad Brandon 016 */ 017public class Translation 018{ 019 private String name; 020 private final Map<String, Fragment> fragments = new LinkedHashMap<String, Fragment>(); 021 private final Collection<String> ignorePatterns = new ArrayList<String>(); 022 023 /** 024 * The library translation to which this translation belongs. 025 */ 026 private LibraryTranslation libraryTranslation; 027 028 /** 029 * Gets the LibraryTranslation to which this Translation belongs. 030 * 031 * @return LibraryTranslation 032 */ 033 protected LibraryTranslation getLibraryTranslation() 034 { 035 // should never happen, but it doesn't hurt to be safe 036 if (this.libraryTranslation == null) 037 { 038 throw new LibraryException("Translation.getLibraryTranslation - libraryTranslation can not be null"); 039 } 040 return libraryTranslation; 041 } 042 043 /** 044 * Sets the LibraryTranslation to which this Translation belongs. 045 * 046 * @param translation the LibraryTranslation to which this Translation belongs. 047 */ 048 protected void setLibraryTranslation(final LibraryTranslation translation) 049 { 050 libraryTranslation = translation; 051 } 052 053 /** 054 * Gets the fragment matching (using regular expressions) the specified name. 055 * 056 * @param name the name of the fragment to retrieve. 057 * @return Fragment 058 */ 059 protected Fragment getFragment(final String name) 060 { 061 Fragment fragment = null; 062 // search through the names and the first name that matches 063 // one of the names return the value of that name. 064 for (String nextName : fragments.keySet()) 065 { 066 if (name.matches(nextName)) 067 { 068 fragment = fragments.get(nextName); 069 } 070 } 071 072 // if the fragment is null, and the name isn't in an ignorePattern 073 // element, then give an error 074 if (fragment == null && !this.isIgnorePattern(name)) 075 { 076 // TODO: make this work correctly with unsupported functions. 077 078 /* 079 * logger.error("ERROR! expression fragment '" + name + "' is not 080 * currently supported --> add a <fragment/> with " + " a name that 081 * matches this expression to your translation file " + "'" + 082 * this.getLibraryTranslation().getFile() + "' to enable support"); 083 */ 084 } 085 return fragment; 086 } 087 088 /** 089 * Adds a new Translation fragment to the Translation. 090 * 091 * @param fragment new Translation fragment 092 */ 093 public void addFragment(final Fragment fragment) 094 { 095 ExceptionUtils.checkNull( 096 "fragment", 097 fragment); 098 fragment.setTranslation(this); 099 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}