001package org.andromda.repositories.emf;
002
003import java.io.InputStream;
004import java.net.URL;
005import java.util.Date;
006import java.util.HashMap;
007import java.util.List;
008import java.util.Map;
009import org.andromda.core.common.AndroMDALogger;
010import org.andromda.core.common.ResourceUtils;
011import org.apache.log4j.Logger;
012import org.eclipse.emf.common.util.URI;
013import org.eclipse.emf.ecore.resource.impl.ExtensibleURIConverterImpl;
014
015/**
016 * Extends the default URIConverterImpl to be able to discover the physical path of URIs when
017 * given the moduleSearchPaths.
018 *
019 * @author Chad Brandon
020 * @author Bob Fields
021 */
022public class EMFURIConverter
023    extends ExtensibleURIConverterImpl
024    // Use URIConverterImpl for UML2 2.x
025{
026    /**
027     * Creates a new instance of EMFURIConverter taking the <code>moduleSearchPaths</code>
028     * and the existing URI Map as arguments. These are the paths used to attempt to normalize a given URI during
029     * the call to {@link #normalize(URI)} provided that it couldn't be found in the normal manner.
030     *
031     * @param moduleSearchPaths the paths to search for modules.
032     * @param uriMap
033     */
034    public EMFURIConverter(final List<String> moduleSearchPaths, Map<URI, URI> uriMap)
035    {
036        this.normalizedUris = uriMap;
037        this.moduleSearchPaths = moduleSearchPaths;
038        if (logger.isDebugEnabled())
039        {
040            for (final String path : moduleSearchPaths)
041            {
042                logger.debug("Model search path:" + path);
043            }
044        }
045    }
046
047    /**
048     * Creates a new instance of EMFURIConverter taking the <code>moduleSearchPaths</code>
049     * as an argument. These are the paths used to attempt to normalize a given URI during
050     * the call to {@link #normalize(URI)} provided that it couldn't be found in the normal manner.
051     *
052     * @param moduleSearchPaths the paths to search for modules.
053     */
054    public EMFURIConverter(final List<String> moduleSearchPaths)
055    {
056        this.moduleSearchPaths = moduleSearchPaths;
057        if (logger.isDebugEnabled())
058        {
059            for (final String path : moduleSearchPaths)
060            {
061                logger.debug("Model search path:" + path);
062            }
063        }
064    }
065
066    /**
067     * Stores the module search paths.
068     */
069    private List<String> moduleSearchPaths;
070
071    /**
072     * Stores the URIs that have been normalized.
073     */
074    private Map<URI, URI> normalizedUris = new HashMap<URI, URI>();
075
076    /**
077     * The logger instance.
078     */
079    private static final Logger logger = Logger.getLogger(EMFURIConverter.class);
080
081    /**
082     * Overridden to provide the normalization of uris given the module search paths.
083     *
084     * @see org.eclipse.emf.ecore.resource.URIConverter#normalize(org.eclipse.emf.common.util.URI)
085     */
086    public URI normalize(final URI uri)
087    {
088        URI normalizedUri = super.normalize(uri);
089        if (normalizedUri.equals(uri))
090        {
091            if (this.moduleSearchPaths != null)
092            {
093                if (!this.normalizedUris.containsKey(uri))
094                {
095                    final String resourceName = uri.toString().replaceAll(
096                            ".*(\\\\+|/)",
097                            "");
098                    for (final String searchPath : moduleSearchPaths)
099                    {
100                        Date now1 = new Date();
101                        final URI fileURI = EMFRepositoryFacadeUtils.createUri(ResourceUtils.normalizePath(searchPath));
102                        long ms1 = new Date().getTime() - now1.getTime();
103                        if (fileURI != null && fileURI.lastSegment() != null && fileURI.lastSegment().equals(resourceName))
104                        {
105                            String ms = (ms1 > 100 ? ms1 + " ms" : "");
106                            AndroMDALogger.info("referenced model --> '" + fileURI + "' " + ms);
107                            normalizedUri = fileURI;
108                            this.normalizedUris.put(
109                                uri,
110                                normalizedUri);
111                            break;
112                        }
113
114                        final String completePath = ResourceUtils.normalizePath(searchPath + '/' + resourceName);
115
116                        try
117                        {
118                            Date now = new Date();
119                            InputStream stream;
120                            URL url = ResourceUtils.toURL(completePath);
121                            if (url != null)
122                            {
123                                try
124                                {
125                                    stream = url.openStream();
126                                    stream.close();
127                                    long ms2 = new Date().getTime() - now.getTime();
128                                    String ms = (ms2 > 100 ? ms2 + " ms" : "");
129                                    AndroMDALogger.info("referenced model --> '" + url + "' " + ms);
130                                }
131                                catch (final Exception exception)
132                                {
133                                    url = null;
134                                }
135                                finally
136                                {
137                                    stream = null;
138                                }
139                                if (url != null)
140                                {
141                                    long ms2 = new Date().getTime() - now.getTime();
142                                    normalizedUri = EMFRepositoryFacadeUtils.createUri(url.toString());
143                                    this.normalizedUris.put(
144                                        uri,
145                                        normalizedUri);
146                                    if (AndroMDALogger.isDebugEnabled())
147                                    {
148                                        AndroMDALogger.debug("loaded model --> '" + url + "' " + ms2 + " ms");
149                                    }
150                                    break;
151                                }
152                            }
153                        }
154                        catch (final Exception exception)
155                        {
156                            logger.debug(
157                                "Caught exception in EMFURIConverter",
158                                exception);
159                        }
160                        long ms2 = new Date().getTime() - now1.getTime();
161                        String ms = (ms2 > 100 ? ms2 + " ms" : "");
162                        if (AndroMDALogger.isDebugEnabled())
163                        {
164                            AndroMDALogger.debug("loaded model --> '" + fileURI + "' " + ms);
165                        }
166                    }
167
168                    // - if the normalized URI isn't part of the module search path,
169                    //   still store it so we don't continue to look it up each time (which is really slow)
170                    if (!this.normalizedUris.containsKey(uri))
171                    {
172                        this.normalizedUris.put(
173                            uri,
174                            normalizedUri);
175                    }
176                }
177                else
178                {
179                    normalizedUri = this.normalizedUris.get(uri);
180                }
181            }
182        }
183
184        return normalizedUri;
185    }
186}