Coverage Report - org.argouml.model.mdr.XmiReaderImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
XmiReaderImpl
24%
53/217
15%
10/66
5.353
 
 1  
 /* $Id: XmiReaderImpl.java 18631 2010-08-08 06:49:47Z linus $
 2  
  *****************************************************************************
 3  
  * Copyright (c) 2005,2010 Contributors - see below
 4  
  * All rights reserved. This program and the accompanying materials
 5  
  * are made available under the terms of the Eclipse Public License v1.0
 6  
  * which accompanies this distribution, and is available at
 7  
  * http://www.eclipse.org/legal/epl-v10.html
 8  
  *
 9  
  * Contributors:
 10  
  *    Bob Tarling
 11  
  *    Tom Morris
 12  
  *    euluis
 13  
  *****************************************************************************
 14  
  *
 15  
  * Some portions of this file was previously release using the BSD License:
 16  
  */
 17  
 
 18  
 // Copyright (c) 1996-2009 The Regents of the University of California. All
 19  
 // Rights Reserved. Permission to use, copy, modify, and distribute this
 20  
 // software and its documentation without fee, and without a written
 21  
 // agreement is hereby granted, provided that the above copyright notice
 22  
 // and this paragraph appear in all copies.  This software program and
 23  
 // documentation are copyrighted by The Regents of the University of
 24  
 // California. The software program and documentation are supplied "AS
 25  
 // IS", without any accompanying services from The Regents. The Regents
 26  
 // does not warrant that the operation of the program will be
 27  
 // uninterrupted or error-free. The end-user understands that the program
 28  
 // was developed for research purposes and is advised not to rely
 29  
 // exclusively on the program for any reason.  IN NO EVENT SHALL THE
 30  
 // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
 31  
 // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
 32  
 // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 33  
 // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 34  
 // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
 35  
 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 36  
 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 37  
 // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 38  
 // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
 39  
 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 40  
 
 41  
 package org.argouml.model.mdr;
 42  
 
 43  
 import java.io.File;
 44  
 import java.io.FileInputStream;
 45  
 import java.io.FileNotFoundException;
 46  
 import java.io.FileOutputStream;
 47  
 import java.io.IOException;
 48  
 import java.io.InputStream;
 49  
 import java.net.URL;
 50  
 import java.util.Collection;
 51  
 import java.util.Collections;
 52  
 import java.util.List;
 53  
 import java.util.Map;
 54  
 
 55  
 import javax.jmi.reflect.InvalidObjectException;
 56  
 import javax.jmi.reflect.RefObject;
 57  
 import javax.jmi.reflect.RefPackage;
 58  
 import javax.jmi.xmi.MalformedXMIException;
 59  
 import javax.xml.parsers.ParserConfigurationException;
 60  
 import javax.xml.parsers.SAXParser;
 61  
 import javax.xml.parsers.SAXParserFactory;
 62  
 import javax.xml.transform.Transformer;
 63  
 import javax.xml.transform.TransformerConfigurationException;
 64  
 import javax.xml.transform.TransformerException;
 65  
 import javax.xml.transform.TransformerFactory;
 66  
 import javax.xml.transform.sax.SAXSource;
 67  
 import javax.xml.transform.sax.SAXTransformerFactory;
 68  
 import javax.xml.transform.stream.StreamResult;
 69  
 import javax.xml.transform.stream.StreamSource;
 70  
 
 71  
 import org.apache.log4j.Logger;
 72  
 import org.argouml.model.UmlException;
 73  
 import org.argouml.model.XmiException;
 74  
 import org.argouml.model.XmiReader;
 75  
 import org.netbeans.api.mdr.MDRepository;
 76  
 import org.netbeans.api.xmi.XMIReader;
 77  
 import org.netbeans.api.xmi.XMIReaderFactory;
 78  
 import org.netbeans.lib.jmi.xmi.InputConfig;
 79  
 import org.netbeans.lib.jmi.xmi.UnknownElementsListener;
 80  
 import org.netbeans.lib.jmi.xmi.XMIHeaderConsumer;
 81  
 import org.omg.uml.UmlPackage;
 82  
 import org.openide.ErrorManager;
 83  
 import org.xml.sax.InputSource;
 84  
 import org.xml.sax.SAXException;
 85  
 import org.xml.sax.SAXParseException;
 86  
 import org.xml.sax.XMLFilter;
 87  
 import org.xml.sax.XMLReader;
 88  
 
 89  
 /**
 90  
  * A wrapper around the genuine XmiReader that provides public access with no
 91  
  * knowledge of actual UML implementation.
 92  
  *
 93  
  * @author Bob Tarling
 94  
  */
 95  
 class XmiReaderImpl implements XmiReader, UnknownElementsListener,
 96  
         XMIHeaderConsumer {
 97  
 
 98  
     /**
 99  
      * Logger.
 100  
      */
 101  900
     private static final Logger LOG = Logger.getLogger(XmiReaderImpl.class);
 102  
 
 103  
     private MDRModelImplementation modelImpl;
 104  
 
 105  
     private XmiReferenceResolverImpl resolver;
 106  
 
 107  
     /**
 108  
      * Flag indicating unknown element was found in XMI file.
 109  
      */
 110  
     private boolean unknownElement;
 111  
 
 112  
     /**
 113  
      * Name of first unknown element found (if not a UML 1.3 name).
 114  
      */
 115  
     private String unknownElementName;
 116  
 
 117  
     /**
 118  
      * Flag indicating that we think unknown element was due to a UML 1.3 file.
 119  
      */
 120  
     private boolean uml13;
 121  
 
 122  
     /**
 123  
      * Elements to ignore errors on if they aren't found in the metamodel.
 124  
      */
 125  900
     private String[] ignoredElements = new String[] {};
 126  
 
 127  
     /**
 128  
      * Flag indicating that we stripped at least one diagram during the import.
 129  
      */
 130  
     private int ignoredElementCount;
 131  
     
 132  
     /**
 133  
      * String that we pulled from the header of the XMI file
 134  
      */
 135  
     private String xmiHeader;
 136  
 
 137  
 
 138  
     /**
 139  
      * Constructor for XMIReader.
 140  
      * @param parentModelImplementation The ModelImplementation
 141  
      */
 142  900
     XmiReaderImpl(MDRModelImplementation parentModelImplementation) {
 143  900
         modelImpl = parentModelImplementation;
 144  900
     }
 145  
     
 146  
     public Collection parse(InputSource inputSource, boolean readOnly)
 147  
         throws UmlException {
 148  
         
 149  900
         Collection<RefObject> newElements = Collections.emptyList();
 150  
 
 151  900
         String extentBase = inputSource.getPublicId();
 152  900
         if (extentBase == null) {
 153  0
             extentBase = inputSource.getSystemId();
 154  
         }
 155  900
         if (extentBase == null) {
 156  0
             extentBase = MDRModelImplementation.MODEL_EXTENT_NAME;
 157  
         }
 158  900
         String extentName = extentBase;
 159  900
         UmlPackage extent = 
 160  
             (UmlPackage) modelImpl.getRepository().getExtent(extentName);
 161  900
         int serial = 1;
 162  900
         while (extent != null) {
 163  0
             extentName = extentBase + " " + serial;
 164  0
             serial++;
 165  0
             extent = (UmlPackage) modelImpl.getRepository().getExtent(
 166  
                     extentName);
 167  
         }
 168  
 
 169  900
         extent = (UmlPackage) modelImpl.createExtent(extentName, readOnly);
 170  900
         if (extent == null) {
 171  0
             LOG.error("Failed to create extent " + extentName);
 172  
         }
 173  
         
 174  
         try {
 175  900
             LOG.info("Loading to extent '" + extentName + "' " + extent);
 176  
 
 177  900
             InputConfig config = new InputConfig();
 178  900
             config.setUnknownElementsListener(this);
 179  900
             config.setUnknownElementsIgnored(true);
 180  
 
 181  900
             String pId = inputSource.getPublicId();
 182  900
             String sId = modelImpl.getPublic2SystemIds().get(pId);
 183  900
             if (sId != null) {
 184  0
                 if (sId.equals(inputSource.getSystemId())) {
 185  0
                     LOG.info("Attempt to reread profile - ignoring - "
 186  
                             + "publicId = \"" + pId + "\";  systemId = \""
 187  
                             + sId + "\".");
 188  0
                     return Collections.emptySet();
 189  
                 } else {
 190  0
                     throw new UmlException("Profile with the duplicate publicId "
 191  
                             + "is being loaded! publicId = \"" + pId
 192  
                             + "\"; existing systemId = \""
 193  
                             + modelImpl.getPublic2SystemIds().get(pId)
 194  
                             + "\"; new systemId = \"" + sId + "\".");
 195  
                 }
 196  
             }
 197  900
             resolver = new XmiReferenceResolverImpl(new RefPackage[] {extent},
 198  
                     config, modelImpl.getObjectToId(), 
 199  
                     modelImpl.getPublic2SystemIds(), modelImpl.getIdToObject(), 
 200  
                     modelImpl.getSearchPath(), 
 201  
                     readOnly, 
 202  
                     inputSource.getPublicId(), inputSource.getSystemId(),
 203  
                     modelImpl);
 204  900
             config.setReferenceResolver(resolver);
 205  900
             config.setHeaderConsumer(this);
 206  
             
 207  900
             XMIReader xmiReader =
 208  
                     XMIReaderFactory.getDefault().createXMIReader(config);
 209  
 
 210  
             /*
 211  
              * MDR has a hardcoded printStackTrace on all exceptions,
 212  
              * even if they're caught, which is unsightly, so we handle
 213  
              * unknown elements ourselves rather than letting MDR throw
 214  
              * an exception for us to catch.
 215  
              * 
 216  
              * org/netbeans/lib/jmi/util/Logger.java
 217  
              * 
 218  
              * This can be uses to disable logging.  Default output is 
 219  
              * System.err
 220  
              * setProperty("org.netbeans.lib.jmi.Logger.fileName", "")
 221  
              *              org.netbeans.mdr.Logger
 222  
              * 
 223  
              * The property org.netbeans.lib.jmi.Logger controls the minimum 
 224  
              * severity level for logging
 225  
              */
 226  
             // Turn off NetBeans logging to System.err
 227  
 //            System.setProperty("org.netbeans.lib.jmi.Logger.fileName", "");
 228  
             // Set minimum severity level for MDR
 229  
 //            System.setProperty("org.netbeans.lib.jmi.Logger", 
 230  
 //                    Integer.toString(ErrorManager.INFORMATIONAL));
 231  900
             InputConfig config2 = (InputConfig) xmiReader.getConfiguration();
 232  900
             config2.setUnknownElementsListener(this);
 233  900
             config2.setUnknownElementsIgnored(true);
 234  900
             unknownElement = false;
 235  900
             uml13 = false;
 236  900
             ignoredElementCount = 0;
 237  
 
 238  
             // Disable event delivery during model load
 239  900
             modelImpl.getModelEventPump().stopPumpingEvents();
 240  
 
 241  
             try {
 242  900
                 String systemId = inputSource.getSystemId();
 243  
                 // If we've got a streaming input, copy it to make sure we'll
 244  
                 // be able to rewind it if necessary
 245  900
                 if (inputSource.getByteStream() != null
 246  
                         || inputSource.getCharacterStream() != null) {
 247  0
                     File file = copySource(inputSource);
 248  0
                     systemId = file.toURI().toURL().toExternalForm();
 249  0
                     String publicId = inputSource.getPublicId();
 250  0
                     inputSource = new InputSource(systemId);
 251  0
                     inputSource.setPublicId(publicId);                    
 252  
                 }
 253  900
                 MDRepository repository = modelImpl.getRepository();
 254  
                 
 255  
                 // Use a transaction to avoid the performance penalty (3x) of 
 256  
                 // MDR's autocommit mode
 257  900
                 repository.beginTrans(true);
 258  
 
 259  900
                 newElements = xmiReader.read(inputSource.getByteStream(),
 260  
                         systemId, extent);
 261  
                 
 262  
                 // If a UML 1.3 file, attempt to upgrade it to UML 1.4
 263  900
                 if (uml13) {
 264  
                     // Roll back transaction from first attempt & start new one
 265  0
                     repository.endTrans(true);
 266  0
                     repository.beginTrans(true);
 267  
 
 268  
                     // Clear the associated ID maps & reset starting collection
 269  0
                     resolver.clearIdMaps();
 270  
 
 271  0
                     newElements = convertAndLoadUml13(inputSource.getSystemId(),
 272  
                             extent, xmiReader, inputSource);
 273  
                 }
 274  
 
 275  
                 // Commit our transaction
 276  900
                 repository.endTrans();
 277  0
             } catch (Throwable e) {
 278  
                 // Roll back transaction to remove any partial results read
 279  
                 try {
 280  0
                     modelImpl.getRepository().endTrans(true);
 281  0
                 } catch (Throwable e2) {
 282  
                     // Ignore any error.  The transaction may already have
 283  
                     // been unwound as part of exception processing by MDR
 284  0
                 }
 285  0
                 if (e instanceof MalformedXMIException) {
 286  0
                     throw (MalformedXMIException) e;
 287  0
                 } else if (e instanceof IOException) {
 288  0
                     throw (IOException) e;
 289  
                 } else {
 290  
                     // We shouldn't get here, but just in case...
 291  
                     // We want a wide exception catcher to make sure our
 292  
                     // transaction always gets ended
 293  0
                     e.printStackTrace();
 294  0
                     throw new MalformedXMIException();
 295  
                 }
 296  
             } finally {
 297  900
                 modelImpl.getModelEventPump().startPumpingEvents();
 298  900
             }
 299  
 
 300  900
             if (unknownElement) {
 301  0
                 modelImpl.deleteExtent(extent);
 302  0
                 throw new XmiException("Unknown element in XMI file : "
 303  
                         + unknownElementName);
 304  
             }
 305  
 
 306  900
             if (ignoredElementCount > 0) {
 307  0
                 LOG.warn("Ignored one or more elements from list "
 308  
                         + ignoredElements);
 309  
             }
 310  
 
 311  0
         } catch (MalformedXMIException e) {
 312  
             // If we can find a nested SAX exception, it will have information
 313  
             // on the line number, etc.
 314  0
             ErrorManager.Annotation[] annotations = 
 315  
                 ErrorManager.getDefault().findAnnotations(e);
 316  0
             for (ErrorManager.Annotation annotation : annotations) {
 317  0
                 Throwable throwable = annotation.getStackTrace();
 318  0
                 if (throwable instanceof SAXParseException) {
 319  0
                     SAXParseException spe = (SAXParseException) throwable;
 320  0
                     throw new XmiException(spe.getMessage(), spe.getPublicId(),
 321  
                             spe.getSystemId(), spe.getLineNumber(), 
 322  
                             spe.getColumnNumber(), e);
 323  0
                 } else if (throwable instanceof SAXException) {
 324  0
                     SAXException se = (SAXException) throwable;
 325  0
                     Exception e1 = se.getException();
 326  0
                     if (e1 instanceof org.argouml.model.XmiReferenceRuntimeException) {
 327  0
                         String href = 
 328  
                             ((org.argouml.model.XmiReferenceRuntimeException) e1)
 329  
                                 .getReference();
 330  0
                         throw new org.argouml.model.XmiReferenceException(href,
 331  
                                 e);
 332  
                     }
 333  0
                     throw new XmiException(se.getMessage(), se);
 334  
                 }
 335  
             }
 336  0
             modelImpl.deleteExtent(extent);
 337  0
             throw new XmiException(e);
 338  0
         } catch (IOException e) {
 339  
             try {
 340  0
                 modelImpl.deleteExtent(extent);
 341  0
             } catch (InvalidObjectException e2) {
 342  
                 // Ignore if the extent never got created or has been deleted
 343  0
             }
 344  0
             throw new XmiException(e);
 345  900
         }
 346  
 
 347  900
         return newElements;
 348  
     }
 349  
 
 350  
 
 351  
     private Collection<RefObject> convertAndLoadUml13(String systemId,
 352  
             RefPackage extent, XMIReader xmiReader, InputSource input)
 353  
         throws FileNotFoundException, UmlException, IOException,
 354  
             MalformedXMIException {
 355  
         
 356  0
         LOG.info("XMI file doesn't appear to be UML 1.4 - "
 357  
                 + "attempting UML 1.3->UML 1.4 conversion");
 358  0
         final String[] transformFiles = new String[] { 
 359  
             "NormalizeNSUML.xsl",
 360  
             "uml13touml14.xsl", };
 361  
 
 362  0
         unknownElement = false;
 363  
         // InputSource xformedInput = chainedTransform(transformFiles, pIs);
 364  0
         InputSource xformedInput = serialTransform(transformFiles,
 365  
                 input);
 366  0
         xformedInput.setPublicId(input.getPublicId());
 367  0
         return xmiReader.read(xformedInput.getByteStream(), xformedInput
 368  
                 .getSystemId(), extent);
 369  
     }
 370  
 
 371  
     /*
 372  
      * @see org.argouml.model.XmiReader#getXMIUUIDToObjectMap()
 373  
      */
 374  
     public Map<String, Object> getXMIUUIDToObjectMap() {
 375  0
         if (resolver != null) {
 376  0
             return resolver.getIdToObjectMap();
 377  
         }
 378  0
         return null;
 379  
     }
 380  
 
 381  
     private static final String STYLE_PATH =
 382  
         "/org/argouml/model/mdr/conversions/";
 383  
 
 384  
     /*
 385  
      * A near clone of this code works fine outside of ArgoUML, but throws a
 386  
      * null pointer exception during the transform when run within ArgoUML I
 387  
      * think it's something to do with the class libraries being used, but I
 388  
      * can't figure out what, so I've done a simpler, less efficient stepwise
 389  
      * translation below in serialTransform
 390  
      */
 391  
     private InputSource chainedTransform(String[] styles, InputSource input)
 392  
         throws XmiException {
 393  0
         SAXTransformerFactory stf =
 394  
             (SAXTransformerFactory) TransformerFactory.newInstance();
 395  
 
 396  
         // TODO: Reconfigure exception handling to distinguish between errors
 397  
         // that are possible due to bad input data and those that represent
 398  
         // unexpected processing errors.
 399  
         try {
 400  
             // Set up reader to be first filter in chain
 401  0
             SAXParserFactory spf = SAXParserFactory.newInstance();
 402  0
             SAXParser parser = spf.newSAXParser();
 403  0
             XMLReader last = parser.getXMLReader();
 404  
 
 405  
             // Create filter for each style sheet and chain to previous
 406  
             // filter/reader
 407  0
             for (int i = 0; i < styles.length; i++) {
 408  0
                 String xsltFileName = STYLE_PATH + styles[i];
 409  0
                 URL xsltUrl = getClass().getResource(xsltFileName);
 410  0
                 if (xsltUrl == null) {
 411  0
                     throw new IOException("Error opening XSLT style sheet : "
 412  
                             + xsltFileName);
 413  
                 }
 414  0
                 StreamSource xsltStreamSource =
 415  
                     new StreamSource(xsltUrl.openStream());
 416  0
                 xsltStreamSource.setSystemId(xsltUrl.toExternalForm());
 417  0
                 XMLFilter filter = stf.newXMLFilter(xsltStreamSource);
 418  
 
 419  0
                 filter.setParent(last);
 420  0
                 last = filter;
 421  
             }
 422  
 
 423  0
             SAXSource transformSource = new SAXSource(last, input);
 424  
 
 425  
             // Create temporary file for output
 426  
             // TODO: we should be able to chain this directly to XMI reader
 427  0
             File tmpFile = File.createTempFile("zargo_model_", ".xmi");
 428  0
             tmpFile.deleteOnExit();
 429  0
             StreamResult result =
 430  
                 new StreamResult(
 431  
                     new FileOutputStream(tmpFile));
 432  
 
 433  0
             Transformer transformer = stf.newTransformer();
 434  0
             transformer.transform(transformSource, result);
 435  
 
 436  0
             return new InputSource(new FileInputStream(tmpFile));
 437  
 
 438  0
         } catch (SAXException e) {
 439  0
             throw new XmiException(e);
 440  0
         } catch (ParserConfigurationException e) {
 441  0
             throw new XmiException(e);
 442  0
         } catch (IOException e) {
 443  0
             throw new XmiException(e);
 444  0
         } catch (TransformerConfigurationException e) {
 445  0
             throw new XmiException(e);
 446  0
         } catch (TransformerException e) {
 447  0
             throw new XmiException(e);
 448  
         }
 449  
 
 450  
     }
 451  
 
 452  
     private InputSource serialTransform(String[] styles, InputSource input)
 453  
         throws UmlException {
 454  0
         SAXSource myInput = new SAXSource(input);
 455  0
         SAXTransformerFactory stf =
 456  
             (SAXTransformerFactory) TransformerFactory.newInstance();
 457  
         try {
 458  
 
 459  0
             for (int i = 0; i < styles.length; i++) {
 460  
                 // Set up source for style sheet
 461  0
                 String xsltFileName = STYLE_PATH + styles[i];
 462  0
                 if (LOG.isInfoEnabled()) {
 463  0
                     LOG.info("Transforming with " + xsltFileName);
 464  
                 }
 465  0
                 URL xsltUrl = getClass().getResource(xsltFileName);
 466  0
                 if (xsltUrl == null) {
 467  0
                     throw new UmlException("Error opening XSLT style sheet : "
 468  
                             + xsltFileName);
 469  
                 }
 470  0
                 StreamSource xsltStreamSource =
 471  
                     new StreamSource(xsltUrl.openStream());
 472  0
                 xsltStreamSource.setSystemId(xsltUrl.toExternalForm());
 473  
 
 474  
                 // Create & set up temporary output file
 475  0
                 File tmpOutFile = File.createTempFile("zargo_model_", ".xmi");
 476  0
                 tmpOutFile.deleteOnExit();
 477  0
                 StreamResult result =
 478  
                     new StreamResult(new FileOutputStream(
 479  
                         tmpOutFile));
 480  
 
 481  
                 // Create transformer and do transformation
 482  0
                 Transformer transformer = stf.newTransformer(xsltStreamSource);
 483  0
                 transformer.transform(myInput, result);
 484  
 
 485  0
                 LOG.info("Wrote converted XMI file - " + tmpOutFile
 486  
                         + " converted using : " + xsltFileName);
 487  
 
 488  
                 // Set up for next iteration
 489  0
                 myInput =
 490  
                     new SAXSource(new InputSource(new FileInputStream(
 491  
                         tmpOutFile)));
 492  0
                 myInput.setSystemId(tmpOutFile.toURI().toURL().toExternalForm());
 493  
             }
 494  0
             return myInput.getInputSource();
 495  0
         } catch (IOException e) {
 496  0
             throw new UmlException(e);
 497  0
         } catch (TransformerConfigurationException e) {
 498  0
             throw new UmlException(e);
 499  0
         } catch (TransformerException e) {
 500  0
             throw new UmlException(e);
 501  
         }
 502  
 
 503  
     }
 504  
 
 505  
     private File copySource(InputSource input) throws IOException {
 506  0
         byte[] buf = new byte[2048];
 507  
         int len;
 508  
         
 509  
         // Create & set up temporary output file
 510  0
         File tmpOutFile = File.createTempFile("zargo_model_", ".xmi");
 511  0
         tmpOutFile.deleteOnExit();
 512  0
         FileOutputStream out = new FileOutputStream(tmpOutFile);
 513  
         
 514  
         // TODO: Bob says - Coding by use of side effect here.
 515  
         // Maybe this should be done in a clearer way but it fixes
 516  
         // http://argouml.tigris.org/issues/show_bug.cgi?id=4978
 517  
         // It seems that when loading an XMI that is not contained in a zip
 518  
         // file then the InputStream given as the argument to this method
 519  
         // can't be reused as it is at the end of the stream. In that case
 520  
         // systemId appears to be none-null at this stage.
 521  
         // So if systemId is not null we recreate the InputSource.
 522  0
         String systemId = input.getSystemId();
 523  0
         if (systemId != null) {
 524  0
             input = new InputSource(new URL(systemId).openStream());
 525  
         }
 526  
         
 527  0
         InputStream in = input.getByteStream();
 528  
         
 529  0
         while ((len = in.read(buf)) >= 0) {
 530  0
             out.write(buf, 0, len);
 531  
         }
 532  0
         out.close();
 533  
 
 534  0
         LOG.debug("Wrote copied XMI file to " + tmpOutFile);
 535  0
         return tmpOutFile;
 536  
     }
 537  
 
 538  900
     private static final String UML_13_ELEMENTS[] = 
 539  
     {
 540  
         "TaggedValue.value",
 541  
         "TaggedValue.tag",
 542  
         "ModelElement.templateParameter2",
 543  
         "ModelElement.templateParameter3",
 544  
         "Classifier.structuralFeature",
 545  
         "Classifier.parameter",
 546  
         "AssociationEnd.type",
 547  
         "Node.resident",
 548  
         "ElementResidence.implementationLocation",
 549  
         "TemplateParameter.modelElement",
 550  
         "TemplateParameter.modelElement2",
 551  
         "Constraint.constrainedElement2",
 552  
         "UseCase.include2",
 553  
         "StateMachine.subMachineState",
 554  
         "ClassifierRole.message1",
 555  
         "ClassifierRole.message2",
 556  
         "Message.message3",
 557  
         "Message.message4",
 558  
         "ElementImport.modelElement",
 559  
 
 560  
         "ModelElement.elementResidence",
 561  
         "ModelElement.presentation",
 562  
         "ModelElement.supplierDependency",
 563  
         "ModelElement.templateParameter2",
 564  
         "ModelElement.templateParameter3",
 565  
         "ModelElement.binding",
 566  
         "GeneralizableElement.specialization",
 567  
         "Classifier.associationEnd",
 568  
         "Classifier.participant",
 569  
         "Operation.method",
 570  
         "Stereotype.extendedElement",
 571  
         "Stereotype.requiredTag",
 572  
         "TaggedValue.stereotype",
 573  
         "Signal.context",
 574  
         "Signal.reception",
 575  
         "Signal.sendAction",
 576  
 
 577  
         "UseCase.include2",
 578  
         "UseCase.extend2",
 579  
         "ExtensionPoint.extend",
 580  
         "Link.stimulus",
 581  
         "Instance.attributeLink",
 582  
         "Action.stimulus",
 583  
         "Event.state",
 584  
         "Event.transition",
 585  
         "Transition.state",
 586  
 
 587  
         "ClassifierRole.message1",
 588  
         "ClassifierRole.message2",
 589  
         "Message.message3",
 590  
         "Message.message4",
 591  
 
 592  
         "Action.state1",
 593  
         "Action.state2",
 594  
         "Action.state3",
 595  
         "Instance.stimulus1",
 596  
         "Instance.stimulus2",
 597  
         "Instance.stimulus3",
 598  
 
 599  
     };
 600  
     
 601  
 
 602  
     public void elementFound(String name) {
 603  
         // Silently ignore anything specified by caller attempt to continue
 604  0
         if (ignoredElements != null) {
 605  0
             for (int i = 0; i < ignoredElements.length; i++) {
 606  0
                 if (name.equals(ignoredElements[i])) {
 607  0
                     ignoredElementCount++;
 608  0
                     return;
 609  
                 }
 610  
             }
 611  
         }
 612  
         
 613  0
         if (name.startsWith("Foundation.")) {
 614  0
             uml13 = true;
 615  0
             return;
 616  
         }
 617  
 
 618  0
         for (int i = 0; i < UML_13_ELEMENTS.length; i++) {
 619  0
             if (name.endsWith(UML_13_ELEMENTS[i])) {
 620  0
                 uml13 = true;
 621  0
                 return;
 622  
             }
 623  
         }
 624  
 
 625  0
         unknownElement = true;
 626  0
         if (unknownElementName == null) {
 627  0
             unknownElementName = name;
 628  
         }
 629  0
         LOG.error("Unknown XMI element named : " + name);
 630  
         
 631  0
     }
 632  
 
 633  
 
 634  
     public boolean setIgnoredElements(String[] elementNames) {
 635  0
         if (elementNames == null) {
 636  0
             ignoredElements = new String[] {};
 637  
         } else {
 638  0
             ignoredElements = elementNames;
 639  
         }
 640  0
         return true;
 641  
     }
 642  
 
 643  
 
 644  
     public String[] getIgnoredElements() {
 645  0
         return ignoredElements;
 646  
     }
 647  
 
 648  
 
 649  
     public int getIgnoredElementCount() {
 650  0
         return ignoredElementCount;
 651  
     }
 652  
 
 653  
 
 654  
     public String getTagName() {
 655  0
         return "XMI";
 656  
     }
 657  
 
 658  
     public void addSearchPath(String path) {
 659  0
         modelImpl.addSearchPath(path);
 660  0
     }
 661  
 
 662  
     public void removeSearchPath(String path) {
 663  0
         modelImpl.removeSearchPath(path);
 664  0
     }
 665  
 
 666  
     public List<String> getSearchPath() {
 667  0
         return modelImpl.getSearchPath();
 668  
     }
 669  
 
 670  
     public void consumeHeader(InputStream stream) {
 671  
         try {
 672  900
             int length = stream.available();
 673  900
             byte[] bytes = new byte[length];
 674  900
             stream.read(bytes, 0, length);
 675  
             // we presume the stream is encoded using the default char encoding
 676  900
             xmiHeader = new String(bytes);
 677  0
         } catch (IOException e) {
 678  0
             LOG.error("Exception reading XMI file header", e);
 679  900
         }
 680  900
     }
 681  
     
 682  
 
 683  
     public String getHeader() {
 684  0
         return xmiHeader;
 685  
     }
 686  
 
 687  
 }