View Javadoc

1   //
2   // $Revision: 5 $
3   // $LastChangedBy: mhanns $
4   // $Date: 2010-04-01 10:10:45 +0200 (Do, 01 Apr 2010) $
5   // $HeadURL: https://modelrepository.svn.sourceforge.net/svnroot/modelrepository/trunk/repository/src/main/java/de/uni_leipzig/wifa/iwi/mr3/service/impl/CompareProcessorImpl.java $
6   //
7   
8   package de.uni_leipzig.wifa.iwi.mr3.service.impl;
9   
10  import java.io.BufferedWriter;
11  import java.io.IOException;
12  import java.io.StringReader;
13  import java.io.StringWriter;
14  import java.io.Writer;
15  import java.util.Calendar;
16  import java.util.Collections;
17  import java.util.HashMap;
18  
19  import javax.xml.parsers.FactoryConfigurationError;
20  import javax.xml.stream.XMLInputFactory;
21  import javax.xml.stream.XMLStreamException;
22  import javax.xml.stream.XMLStreamReader;
23  
24  import org.apache.axiom.om.OMElement;
25  import org.apache.axiom.om.impl.builder.StAXOMBuilder;
26  import org.apache.log4j.Logger;
27  import org.eclipse.emf.common.util.EList;
28  import org.eclipse.emf.common.util.URI;
29  import org.eclipse.emf.compare.diff.metamodel.DiffFactory;
30  import org.eclipse.emf.compare.diff.metamodel.DiffModel;
31  import org.eclipse.emf.compare.diff.metamodel.ModelInputSnapshot;
32  import org.eclipse.emf.compare.diff.service.DiffService;
33  import org.eclipse.emf.compare.match.metamodel.MatchModel;
34  import org.eclipse.emf.compare.match.service.MatchService;
35  import org.eclipse.emf.compare.util.ModelUtils;
36  import org.eclipse.emf.ecore.EObject;
37  import org.eclipse.emf.ecore.EPackage;
38  import org.eclipse.emf.ecore.EPackage.Registry;
39  import org.eclipse.emf.ecore.resource.ResourceSet;
40  import org.eclipse.emf.ecore.resource.Resource.Factory;
41  import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
42  import org.eclipse.emf.ecore.xmi.XMIResource;
43  import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
44  
45  import de.uni_leipzig.wifa.iwi.mr3.common.Comparison;
46  import de.uni_leipzig.wifa.iwi.mr3.common.Model;
47  import de.uni_leipzig.wifa.iwi.mr3.dao.ModelRepositoryDao;
48  import de.uni_leipzig.wifa.iwi.mr3.service.CompareProcessor;
49  import de.uni_leipzig.wifa.iwi.mr3.service.MRException;
50  import de.uni_leipzig.wifa.iwi.mr3.service.ServiceHelper;
51  
52  /**
53   * Compare processor for comparing two models from the nodespace.
54   */
55  public class CompareProcessorImpl implements CompareProcessor
56  {
57    /** Logger. */
58    private static final Logger LOG = Logger.getLogger(ModelRepositoryServiceImpl.class);
59  
60    /** Dummy URI for in-memory resources. */
61    private static final String DUMMY_URI = "";
62  
63    /** Default content type literal. */
64    private static final String DEFAULT_CONTENT_TYPE = "*";
65  
66    /** XMI resource factory. */
67    private static final Factory RESOURCE_FACTORY = new XMIResourceFactoryImpl();
68  
69    /** The DAO instance. */
70    private ModelRepositoryDao dao;
71  
72    /** Service helper. */
73    private ServiceHelper helper;
74  
75    /**
76     * @see de.uni_leipzig.wifa.iwi.mr3.service.CompareProcessor#process(java.lang.String,
77     *      java.lang.String)
78     * @param leftUri
79     *          URI of left model
80     * @param rightUri
81     *          URI of right model
82     * @return Comparison result
83     * @throws MRException
84     *           Service level exception
85     */
86    public Comparison process(final String leftUri, final String rightUri) throws MRException
87    {
88      final long startTime = System.currentTimeMillis();
89  
90      final ResourceSet rset = new ResourceSetImpl();
91      rset.getResourceFactoryRegistry().getContentTypeToFactoryMap().put(DEFAULT_CONTENT_TYPE, RESOURCE_FACTORY);
92      final Registry reg = rset.getPackageRegistry();
93  
94      final XMIResource leftResource = (XMIResource) rset.createResource(URI.createURI(leftUri));
95      final EObject leftModel = getDao().load(leftUri, new HashMap<Object, EObject>());
96      leftResource.getContents().add(leftModel);
97      reg.put(leftUri, leftModel);
98  
99      final XMIResource rightResource = (XMIResource) rset.createResource(URI.createURI(rightUri));
100     final EObject rightModel = getDao().load(rightUri, new HashMap<Object, EObject>());
101     rightResource.getContents().add(rightModel);
102     reg.put(rightUri, rightModel);
103 
104     try
105     {
106       final ResourceSet resourceSet = new ResourceSetImpl();
107       resourceSet.getResourceFactoryRegistry().getContentTypeToFactoryMap().put(DEFAULT_CONTENT_TYPE, RESOURCE_FACTORY);
108       final XMIResource diffModelResource = (XMIResource) resourceSet.createResource(URI.createURI(DUMMY_URI));
109 
110       // save model to string
111       diffModelResource.getContents().add(compare(leftModel, rightModel));
112 
113       final OMElement axiomDiffModel = serializeResource(diffModelResource);
114       final OMElement axiomLeftModel = serializeResource(leftResource);
115       final OMElement axiomRightModel = serializeResource(rightResource);
116 
117       if (LOG.isInfoEnabled())
118       {
119         LOG.info("compare finished after " + (System.currentTimeMillis() - startTime) + " ms.");
120       }
121 
122       final Comparison cmp = wrap(axiomDiffModel, axiomLeftModel, axiomRightModel);
123 
124       if (!(leftModel instanceof EPackage))
125       {
126         final String leftMetaNsUri = ((EPackage) leftModel.eClass().eContainer()).getNsURI();
127         final String rightMetaNsUri = ((EPackage) rightModel.eClass().eContainer()).getNsURI();
128         if (!leftMetaNsUri.equals(rightMetaNsUri))
129         {
130           throw new MRException("Models do not have the same metamodel. Select two models with the same metamodel, please.");
131         }
132         final OMElement metaAxiomModel = serializeMetamodel(leftMetaNsUri, rset);
133         cmp.addReferenced(wrap(metaAxiomModel));
134       }
135       return cmp;
136     }
137     catch (final InterruptedException e)
138     {
139       throw new MRException("error while comparing models [" + leftUri + "] and [" + rightUri + "]", e);
140     }
141     catch (final IOException e)
142     {
143       throw new MRException("error while comparing models [" + leftUri + "] and [" + rightUri + "]", e);
144     }
145     catch (final XMLStreamException e)
146     {
147       throw new MRException("error while comparing models [" + leftUri + "] and [" + rightUri + "]", e);
148     }
149     catch (final FactoryConfigurationError e)
150     {
151       throw new MRException("error while comparing models [" + leftUri + "] and [" + rightUri + "]", e);
152     }
153   }
154 
155   /**
156    * Compares two given models.
157    * 
158    * @param leftModel
159    *          the left model
160    * @param rightModel
161    *          the right model
162    * @return the comparison result snapshot
163    * @throws InterruptedException
164    *           Thrown if user interrupted the task
165    * @throws IOException
166    *           Thrown if processing the model fails
167    */
168   private ModelInputSnapshot compare(final EObject leftModel, final EObject rightModel) throws InterruptedException,
169       IOException
170   {
171     final MatchModel match = MatchService.doMatch(leftModel, rightModel, Collections.<String, Object> emptyMap());
172     LOG.debug(ModelUtils.serialize(match));
173 
174     final DiffModel diff = DiffService.doDiff(match, false);
175     LOG.debug(ModelUtils.serialize(diff));
176 
177     final ModelInputSnapshot snapshot = DiffFactory.eINSTANCE.createModelInputSnapshot();
178     snapshot.setDate(Calendar.getInstance().getTime());
179     snapshot.setMatch(match);
180     snapshot.setDiff(diff);
181     LOG.debug(ModelUtils.serialize(snapshot));
182 
183     return snapshot;
184   }
185 
186   /**
187    * Serializes the given resource into an OMElement.
188    * 
189    * @param resource
190    *          the resource
191    * @return the OMElement
192    * @throws IOException
193    *           If resource handling fails
194    * @throws XMLStreamException
195    *           If creating the XML stream fails
196    */
197   private OMElement serializeResource(final XMIResource resource) throws IOException, XMLStreamException
198   {
199     final StringWriter writer = new StringWriter();
200     final Writer out = new BufferedWriter(writer);
201     resource.save(out, resource.getDefaultSaveOptions());
202     out.flush();
203 
204     // hand over to string reader
205     final StringReader reader = new StringReader(writer.getBuffer().toString());
206 
207     // hand over to XML reader
208     final XMLStreamReader xmlReader = XMLInputFactory.newInstance().createXMLStreamReader(reader);
209 
210     // hand over to AXIOM builder
211     final StAXOMBuilder builder = new StAXOMBuilder(xmlReader);
212     final OMElement axiomModel = builder.getDocumentElement();
213 
214     out.close();
215     writer.close();
216     return axiomModel;
217   }
218 
219   /**
220    * Serializes a (meta)-model needed by the compare process into an OmElement
221    * and registers all its subpackages into the given ResourceSet.
222    * 
223    * @param leftMetaNsUri
224    *          the namespace uri
225    * @param rset
226    *          the resource set
227    * @return the OMElement
228    * @throws IOException
229    *           If resource handling fails
230    * @throws XMLStreamException
231    *           If creating the XML stream fails
232    */
233   private OMElement serializeMetamodel(final String leftMetaNsUri, final ResourceSet rset) throws IOException,
234       XMLStreamException
235   {
236     final EPackage metaPackage = (EPackage) getDao().load(leftMetaNsUri, new HashMap<Object, EObject>());
237     helper.registerAllSubpackages(metaPackage, rset);
238     final XMIResource metaResource = (XMIResource) rset.createResource(URI.createURI(DUMMY_URI));
239 
240     // save model to string
241     final EList<EObject> metaContents = metaResource.getContents();
242     metaContents.add(metaPackage);
243 
244     final StringWriter metaWriter = new StringWriter();
245     final Writer metaOut = new BufferedWriter(metaWriter);
246     metaResource.save(metaOut, metaResource.getDefaultSaveOptions());
247     metaOut.flush();
248 
249     // hand over to string reader
250     final StringReader metaReader = new StringReader(metaWriter.getBuffer().toString());
251 
252     // hand over to XML reader
253     final XMLStreamReader metaXmlReader = XMLInputFactory.newInstance().createXMLStreamReader(metaReader);
254 
255     // hand over to AXIOM builder
256     final StAXOMBuilder metaBuilder = new StAXOMBuilder(metaXmlReader);
257     final OMElement metaAxiomModel = metaBuilder.getDocumentElement();
258     LOG.debug(metaAxiomModel);
259 
260     metaOut.close();
261     metaWriter.close();
262 
263     return metaAxiomModel;
264   }
265 
266   /**
267    * Wrap content into wrapper.
268    *
269    * @param ss
270    *          Snapshot
271    * @param left
272    *          Left model
273    * @param right
274    *          Right model
275    * @return {@link Comparison}
276    */
277   private Comparison wrap(final OMElement ss, final OMElement left, final OMElement right)
278   {
279     final Comparison cmp = new Comparison();
280     cmp.setSnapshot(wrap(ss));
281     cmp.setLeft(wrap(left));
282     cmp.setRight(wrap(right));
283     return cmp;
284   }
285 
286   /**
287    * Wrap content into wrapper.
288    *
289    * @param content
290    *          Content to wrap
291    * @return Wrapper with content inside.
292    */
293   private Model wrap(final OMElement content)
294   {
295     final Model m = new Model();
296     m.setExtraElement(content);
297     return m;
298   }
299 
300   /**
301    * Getter.
302    * 
303    * @return the DAO
304    * @see de.uni_leipzig.wifa.iwi.mr3.service.CompareProcessor#getDao()
305    */
306   public ModelRepositoryDao getDao()
307   {
308     return dao;
309   }
310 
311   /**
312    * Setter.
313    * 
314    * @param dao
315    *          the DAO
316    * @see de.uni_leipzig.wifa.iwi.mr3.service.CompareProcessor#setDao(de.uni_leipzig.wifa.iwi.mr3.dao.ModelRepositoryDao)
317    */
318   public void setDao(final ModelRepositoryDao dao)
319   {
320     this.dao = dao;
321   }
322 
323   /**
324    * Getter.
325    * 
326    * @return the helper
327    */
328   public ServiceHelper getHelper()
329   {
330     return helper;
331   }
332 
333   /**
334    * Setter.
335    * 
336    * @param helper
337    *          the helper to set
338    */
339   public void setHelper(final ServiceHelper helper)
340   {
341     this.helper = helper;
342   }
343 }