1 package org.andromda.core.mdr;
2
3 import java.io.File;
4 import java.io.InputStream;
5 import java.net.MalformedURLException;
6 import java.net.URL;
7 import java.util.HashMap;
8
9 import javax.jmi.reflect.RefPackage;
10
11 import org.andromda.core.common.ResourceUtils;
12 import org.andromda.core.common.AndroMDALogger;
13 import org.apache.commons.lang.StringUtils;
14 import org.apache.log4j.Logger;
15 import org.netbeans.api.xmi.XMIInputConfig;
16 import org.netbeans.lib.jmi.xmi.XmiContext;
17
18 /***
19 * This class supports the expansion of XML HREF references to other modules
20 * within a model. The result of the resolver should be a valid URL. This is
21 * necessary for Magic Draw as it doesn't have the entire model referenced but
22 * just the archived model.
23 *
24 * @author Matthias Bohlen
25 * @author Chad Brandon
26 */
27 public class MDRXmiReferenceResolverContext
28 extends XmiContext
29 {
30
31 private String[] moduleSearchPath;
32
33 private static Logger logger = Logger
34 .getLogger(MDRXmiReferenceResolverContext.class);
35
36 private static final HashMap urlMap = new HashMap();
37
38 /***
39 * Constructs an instance of this class.
40 *
41 * @param extents
42 * @param config
43 */
44 public MDRXmiReferenceResolverContext(
45 RefPackage[] extents,
46 XMIInputConfig config,
47 String[] moduleSearchPath)
48 {
49 super(extents, config);
50 this.moduleSearchPath = moduleSearchPath;
51 }
52
53 /***
54 * @see org.netbeans.lib.jmi.xmi.XmiContext#toURL(java.lang.String)
55 */
56 public URL toURL(String systemId)
57 {
58 if (logger.isDebugEnabled())
59 logger.debug("attempting to resolve Xmi Href --> '" + systemId
60 + "'");
61
62 final String suffix = getSuffix(systemId);
63
64
65
66 String exts = "//.jar|//.zip";
67 String suffixWithExt = suffix.replaceAll(exts, "");
68 URL modelUrl = (URL)urlMap.get(suffixWithExt);
69
70
71 if (modelUrl == null)
72 {
73
74 modelUrl = this.getValidURL(systemId);
75 if (modelUrl == null)
76 {
77
78 String modelUrlAsString = findModuleURL(suffix);
79 if (StringUtils.isNotBlank(modelUrlAsString))
80 {
81 modelUrl = getValidURL(modelUrlAsString);
82 }
83 if (modelUrl == null)
84 {
85
86 modelUrl = this.findModelUrlOnClasspath(systemId);
87 }
88 if (modelUrl == null)
89 {
90
91 modelUrl = super.toURL(systemId);
92 }
93 }
94
95
96
97 if (modelUrl != null)
98 {
99 AndroMDALogger.info("Referenced model --> '" + modelUrl + "'");
100 urlMap.put(suffixWithExt, modelUrl);
101 }
102 }
103 return modelUrl;
104 }
105
106 /***
107 * Finds a module in the module search path.
108 *
109 * @param moduleName the name of the module without any path
110 * @return the complete URL string of the module if found (null if not
111 * found)
112 */
113 private String findModuleURL(String moduleName)
114 {
115 if (moduleSearchPath == null)
116 return null;
117
118 if (logger.isDebugEnabled())
119 logger.debug("findModuleURL: moduleSearchPath.length="
120 + moduleSearchPath.length);
121 for (int i = 0; i < moduleSearchPath.length; i++)
122 {
123 File candidate = new File(moduleSearchPath[i], moduleName);
124 if (logger.isDebugEnabled())
125 logger.debug("candidate '" + candidate.toString() + "' exists="
126 + candidate.exists());
127 if (candidate.exists())
128 {
129 String urlString;
130 try
131 {
132 urlString = candidate.toURL().toExternalForm();
133 }
134 catch (MalformedURLException e)
135 {
136 return null;
137 }
138
139 if (moduleName.endsWith(".zip") || moduleName.endsWith(".jar"))
140 {
141
142 urlString = "jar:" + urlString + "!/"
143 + moduleName.substring(0, moduleName.length() - 4);
144 }
145 return urlString;
146 }
147 }
148 return null;
149 }
150
151 /***
152 * Gets the suffix of the <code>systemId</code>
153 *
154 * @param systemId the system identifier.
155 * @return the suffix as a String.
156 */
157 private String getSuffix(String systemId)
158 {
159 int lastSlash = systemId.lastIndexOf("/");
160 if (lastSlash > 0)
161 {
162 String suffix = systemId.substring(lastSlash + 1);
163 return suffix;
164 }
165 return systemId;
166 }
167
168 /***
169 * The suffixes to use when searching for referenced models on the
170 * classpath.
171 */
172 protected final static String[] CLASSPATH_MODEL_SUFFIXES = new String[]
173 {
174 "xml",
175 "xmi"
176 };
177
178 /***
179 * Searches for the model URL on the classpath.
180 *
181 * @param systemId the system identifier.
182 * @return the suffix as a String.
183 */
184 private URL findModelUrlOnClasspath(String systemId)
185 {
186 String modelName = StringUtils.substringAfterLast(systemId, "/");
187 String dot = ".";
188
189
190 modelName = StringUtils.substringBeforeLast(modelName, dot);
191
192 URL modelUrl = ResourceUtils.getResource(modelName);
193 if (modelUrl == null)
194 {
195 if (CLASSPATH_MODEL_SUFFIXES != null
196 && CLASSPATH_MODEL_SUFFIXES.length > 0)
197 {
198 int suffixNum = CLASSPATH_MODEL_SUFFIXES.length;
199 for (int ctr = 0; ctr < suffixNum; ctr++)
200 {
201 if (logger.isDebugEnabled())
202 logger.debug("searching for model reference --> '"
203 + modelUrl + "'");
204 String suffix = CLASSPATH_MODEL_SUFFIXES[ctr];
205 modelUrl = ResourceUtils.getResource(modelName + dot
206 + suffix);
207 if (modelUrl != null)
208 {
209 break;
210 }
211 }
212 }
213 }
214 return modelUrl;
215 }
216
217 /***
218 * Returns a URL if the systemId is valid. Returns null otherwise. Catches
219 * exceptions as necessary.
220 *
221 * @param systemId the system id
222 * @return the URL (if valid)
223 */
224 private URL getValidURL(String systemId)
225 {
226 try
227 {
228 URL url = new URL(systemId);
229 InputStream stream = url.openStream();
230 stream.close();
231 return url;
232 }
233 catch (Exception e)
234 {
235 return null;
236 }
237 }
238 }