View Javadoc

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          // if the model URL has a suffix of '.zip' or '.jar', get
65          // the suffix without it and store it in the urlMap
66          String exts = "//.jar|//.zip";
67          String suffixWithExt = suffix.replaceAll(exts, "");
68          URL modelUrl = (URL)urlMap.get(suffixWithExt);
69  
70          // Several tries to construct a URL that really exists.
71          if (modelUrl == null)
72          {
73              // If systemId is a valid URL, simply use it
74              modelUrl = this.getValidURL(systemId);
75              if (modelUrl == null)
76              {
77                  // Try to find suffix in module list.
78                  String modelUrlAsString = findModuleURL(suffix);
79                  if (StringUtils.isNotBlank(modelUrlAsString))
80                  {
81                      modelUrl = getValidURL(modelUrlAsString);
82                  }
83                  if (modelUrl == null)
84                  {
85                      // search the classpath
86                      modelUrl = this.findModelUrlOnClasspath(systemId);
87                  }
88                  if (modelUrl == null)
89                  {
90                      // Give up and let superclass deal with it.
91                      modelUrl = super.toURL(systemId);
92                  }
93              }
94              // if we've found the module model, log it
95              // and place it in the map so we don't have to
96              // find it if we need it again.
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                     // typical case for MagicDraw
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         // remove the first prefix because it may be an archive
189         // (like magicdraw)
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 }