Package org.eclipse.wst.xml.core.internal.emf2xml

Source Code of org.eclipse.wst.xml.core.internal.emf2xml.EMF2DOMSSERenderer

/*******************************************************************************
* Copyright (c) 2001, 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/

package org.eclipse.wst.xml.core.internal.emf2xml;


import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jem.util.emf.workbench.ProjectResourceSet;
import org.eclipse.jem.util.emf.workbench.WorkbenchResourceHelperBase;
import org.eclipse.wst.common.internal.emf.resource.EMF2DOMAdapter;
import org.eclipse.wst.common.internal.emf.resource.EMF2DOMRenderer;
import org.eclipse.wst.common.internal.emf.resource.TranslatorResource;
import org.eclipse.wst.common.internal.emf.utilities.DOMUtilities;
import org.eclipse.wst.common.internal.emfworkbench.WorkbenchResourceHelper;
import org.eclipse.wst.common.internal.emfworkbench.integration.ResourceSetWorkbenchEditSynchronizer;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.model.ModelLifecycleEvent;
import org.eclipse.wst.sse.core.internal.provisional.IModelLifecycleListener;
import org.eclipse.wst.sse.core.internal.provisional.IModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IModelStateListener;
import org.eclipse.wst.sse.core.internal.provisional.INodeAdapter;
import org.eclipse.wst.sse.core.internal.provisional.INodeNotifier;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.xml.core.internal.Logger;
import org.eclipse.wst.xml.core.internal.document.DocumentTypeImpl;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
import org.w3c.dom.Node;


public class EMF2DOMSSERenderer extends EMF2DOMRenderer implements IModelStateListener, IModelLifecycleListener {

  protected Object aboutToChangeNode = null;

  protected boolean isBatchChanges = false;

  private boolean isSaving = false;

  private IModelManager modelManager;
 
  private Class resourceClass;
 
  private boolean reverting = false;

  /** The XML DOM model */
  protected IDOMModel xmlModel;

  /** Used internally; the unique id for the xml model */
  protected String xmlModelId;

  protected boolean xmlModelReverted = false;

  public EMF2DOMSSERenderer() {
    super();
  }

  public void accessForRead() {
    if (!resource.isNew()) {
      String id = getModelManagerId();
      getModelManager().getExistingModelForRead(id);
    }
  }

  public void accessForWrite() {
    modelAccessForWrite();
  }

  /**
   * see batchModelEnd
   *
   */

  public void batchModeEnd() {
    getXMLModel().changedModel();
    setRootNodeAdapterNotificationEnabled(true);
    isBatchChanges = false;
  }

  /**
   * batchModeStart and batchModeEnd is a pair that controls notifications,
   * and tread access. They should always be called in a try/finally block.
   *
   * setBatchModel begins the processing where notifications are not sent
   * out on each change, but saved up until the endBatchMode called.
   *
   * This pair of calls can also, indirectly, "lock" the DOM Model to access
   * from only one thread, so it should not be locked for long periods of
   * time. That's also why it is important to have the endBatchMode in a
   * finally block to be sure it is always called, or the DOM will be left
   * in a locked, unusable, state and only shortly away from severere
   * program error.
   *
   * <pre><code>
   * Example
   * </code>
  
   *  try {
   *      batchModelStart();
   *      ...do a some work ...
   *      }
   *    finally {
   *      endBatchMode();
   *      }
   * 
   * 
   * </pre>
   */
  public void batchModeStart() {
    isBatchChanges = true;
    getXMLModel().aboutToChangeModel();
    setRootNodeAdapterNotificationEnabled(false);
  }

  private void cacheSynchronizationStamp() {
    IFile file = WorkbenchResourceHelper.getFile(resource);
    if (file != null) {
      if (xmlModel != null)
        xmlModel.resetSynchronizationStamp(file);
    }
  }

  /**
   * Create a new Document given
   *
   * @aResource.
   */
  protected void createDocument() {
    TranslatorResource res = getResource();
    res.setDefaults();
    IFile file = WorkbenchResourceHelper.getFile(resource);
    InputStream is = DOMUtilities.createHeaderInputStream(res.getDoctype(), res.getPublicId(), res.getSystemId());
    if (is == null)
      return;
    try {
      try {
        List folders = new ArrayList();
        IContainer container = file.getParent();
        while (null != container && !container.exists() && container instanceof IFolder) {
          folders.add(container);
          container = container.getParent();
        }
        IFolder folder = null;
        for (int i = 0; i < folders.size(); i++) {
          folder = (IFolder) folders.get(i);
          folder.create(true, true, null);
        }
        file.create(is, true, null);
        file.setLocal(true, 1, null);
      }
      catch (CoreException e1) {
        Logger.logException(e1);
      }
      finally {
        if (null != is) {
          is.close();
        }
      }
      initializeXMLModel(file, resource.getWriteCount() != 0);
    }
    catch (IOException ex) {
      Logger.log(Logger.ERROR, "IWAE0017E Unexpected IO exception occurred creating xml document");//$NON-NLS-1$
    }
  }

  protected void createDOMTreeIfNecessary() {
    if (needsToCreateDOM)
      createDOMTree();
  }

  protected EMF2DOMAdapter createRootDOMAdapter() {
    return new EMF2DOMSSEAdapter(getResource(), document, this, getResource().getRootTranslator());
  }

  public void deRegisterAsModelLifecycleListener() {
    if (xmlModel != null)
      xmlModel.removeModelLifecycleListener(this);
  }

  public void deRegisterAsModelStateListener() {
    if (xmlModel != null)
      xmlModel.removeModelStateListener(this);
  }

  private void deregisterFromXMLModel() {
   
    deRegisterAsModelStateListener();
    deRegisterAsModelLifecycleListener();
    // This try/catch block is a hack to fix defect 204114. This occurs
    // because
    // the model manager plugin is shut down and unloaded before the j2ee
    // plugin.
    // Calling getModelManager() can result in a class cast exception that
    // should
    // be ignored.
    // ModelManager mgr = null;
    try {
      getModelManager();
    }
    catch (ClassCastException exc) {
      return;
    }
    if (xmlModel != null) {
      int writeCount = resource.getWriteCount();
      int readCount = resource.getReadCount();
      for (int i = 0; i < writeCount; i++)
        xmlModel.releaseFromEdit();
      for (int ii = 0; ii < readCount; ii++)
        xmlModel.releaseFromRead();
    }
    EMF2DOMAdapter adapter = (EMF2DOMAdapter) EcoreUtil.getAdapter(resource.eAdapters(), EMF2DOMAdapter.ADAPTER_CLASS);
    if (adapter != null) {
      adapter.removeAdapters(adapter.getNode());
    }
    xmlModel = null;
    xmlModelId = null;
  }

  public void doSave(OutputStream outputStream, Map options) throws IOException {

    try {
      isSaving = true;
      if (null != outputStream) {
        throw new RuntimeException(this.getClass().getName() + " should not use an OutputStream for saving");} //$NON-NLS-1$
      createDOMTreeIfNecessary();
      ResourceSetWorkbenchEditSynchronizer synchronizer = (ResourceSetWorkbenchEditSynchronizer) ((ProjectResourceSet) resource.getResourceSet()).getSynchronizer();
      IFile aFile = WorkbenchResourceHelper.getFile(resource);
      try {
        synchronizer.preSave(aFile, resource);
        xmlModel.save(aFile);
      }
      catch (CoreException ex) {
        synchronizer.removeFromRecentlySavedList(aFile);
        Logger.logException(ex);
      }
      cacheSynchronizationStamp();
    }
    finally {
      isSaving = false;
    }
  }

  public EMF2DOMAdapter getExistingDOMAdapter(Node node) {
    //IDOMNode xNode = (IDOMNode) node;
    //return (EMF2DOMSSEAdapter) xNode.getAdapterFor(EMF2DOMAdapter.ADAPTER_CLASS);

    INodeNotifier sseNode = (INodeNotifier) node;
    Collection adapters = sseNode.getAdapters();
    for (Iterator iterator = adapters.iterator(); iterator.hasNext();) {
      INodeAdapter adapter = (INodeAdapter) iterator.next();
      // First Check if it's an EMF2DOMAdapter
      if (adapter != null && adapter.isAdapterForType(EMF2DOMAdapter.ADAPTER_CLASS)) {
        // Cast to EMF2DOMSSEAdapter
        EMF2DOMSSEAdapter e2DAdapter = (EMF2DOMSSEAdapter) adapter;
        //Handle the cases where either adapter's target is null
        //Use the resourceClass to make sure the resource type is identical
        if (getResource() == null || e2DAdapter.getTarget() == null)
          if(resourceClass.equals(e2DAdapter.getResourceClass()))
            return e2DAdapter;
          else
            continue;
       
        // First check if targets are resources
        if (e2DAdapter.getTarget() instanceof Resource) {
          /*
           * Now check if it's the right one (Multiple resources
           * could be attached)
           */
          if (e2DAdapter.getTarget() == getResource()) {
            return e2DAdapter;
          }
        } else {
          // Check if targets are EObjects with the same resources
          TranslatorResource myTarget = getResource();
          EObject adapterTarget = (EObject) e2DAdapter.getTarget();
          /*
           * Now check if it's the right one (Multiple resources could
           * be attached)
           */
          if (adapterTarget.eResource() == myTarget || adapterTarget.eResource() == null) {
            return e2DAdapter;
          }
        }
      }
    }
    return null;
 
  }

  protected IModelManager getModelManager() {
    if (modelManager == null)
      modelManager = StructuredModelManager.getModelManager();
    return modelManager;
  }

  /**
   * Return id used to key the XML resource in the XML ModelManager.
   */
  protected String getModelManagerId() {
    if (xmlModelId == null) {
      IFile file = WorkbenchResourceHelper.getFile(getResource());
      if (file != null) {
        xmlModelId = getModelManager().calculateId(file);
      }
      else {
        xmlModelId = resource.getURI() + Long.toString(System.currentTimeMillis());
      }
    }
    return xmlModelId;
  }

  protected ResourceSet getResourceSet() {
    return resource == null ? null : resource.getResourceSet();
  }

  /**
   * Return the DOM model for this resource.
   */
  public IDOMModel getXMLModel() {
    return xmlModel;
  }

  public String getXMLModelId() {
    return xmlModelId;
 
 
  private IDOMModel initializeXMLModel(IFile file, boolean forWrite) throws UnsupportedEncodingException, IOException {
    if (file == null || !file.exists())
      throw new FileNotFoundException((file == null) ? "null" : file.getFullPath().toOSString()); //$NON-NLS-1$
    try {
      IModelManager manager = getModelManager();
      String id = manager.calculateId(file);     
      if (forWrite) {
        IDOMModel mod = (IDOMModel)manager.getExistingModelForEdit(id);
        if (mod == null)
          setXMLModel((IDOMModel) manager.getModelForEdit(file));
        else {
          setXMLModel(mod);
        }
      }
      else {
        IDOMModel mod = (IDOMModel)manager.getExistingModelForRead(id);
        if (mod == null)
          setXMLModel((IDOMModel) manager.getModelForRead(file));
        else {
          setXMLModel(mod);
        }
      }
      setXMLModelId(getXMLModel().getId());
      needsToCreateDOM = false;
    }
    catch (CoreException e) {
      Logger.logException(e);
      return null;
    }
    String id = getXMLModel().getId();
    syncReferenceCounts(id, forWrite);
    if (xmlModel != null)
      document = xmlModel.getDocument();
    return xmlModel;
  }

  public boolean isBatchMode() {
    return isBatchChanges;
  }

  public boolean isModified() {
    return (getXMLModel() != null && getXMLModel().isDirty());
  }

  public boolean isShared() {
   
    if( xmlModel == null) { //resource could be in process of being unloaded - check with model manager
      String id = getModelManagerId();
      return getModelManager().isShared(id);
    }
    if (getResourceSet() == null)
      return false;
    return xmlModel.isShared();
  }

  public boolean isSharedForWrite() {
    if (getResourceSet() == null || xmlModel == null)
      return false;
    return xmlModel.isSharedForEdit();
  }

  protected void loadDocument(InputStream in, Map options) throws IOException {
    if (null != in) {
      throw new RuntimeException(this.getClass().getName() + " should not use an InputStream for loading");} //$NON-NLS-1$
    IFile file = WorkbenchResourceHelper.getFile(resource);
    initializeXMLModel(file, (resource.getWriteCount() != 0));
    cacheSynchronizationStamp();
  }

  protected boolean managesDOMAdapters() {
    return false;
  }

  public void modelAboutToBeChanged(IStructuredModel model) {
    if (model.getStructuredDocument() != null)
      aboutToChangeNode = model.getStructuredDocument().getFirstStructuredDocumentRegion();
  }

  public void modelAboutToBeReinitialized(IStructuredModel structuredModel) {
    // TODO Auto-generated method stub

  }

  private void modelAccessForWrite() {
    String id = getModelManagerId();
    getModelManager().getExistingModelForEdit(id);
  }

  public void modelChanged(IStructuredModel model) {
    if (isBatchChanges)
      return;
    try {
      if (reverting && aboutToChangeNode != null && model.getStructuredDocument() != null
          && model.getStructuredDocument().getFirstStructuredDocumentRegion() != aboutToChangeNode) {
        String id = getModelManagerId();
        IStructuredModel tempModel = null;
        try {
          tempModel = getModelManager().getExistingModelForEdit(id);
          xmlModelReverted = true;
          resource.unload();
        } finally {
          if (tempModel != null && (tempModel.getReferenceCountForEdit() > 0)) {
            tempModel.releaseFromEdit();
          }
          reverting = false;
        }
      }
    } finally {
      aboutToChangeNode = null;
    }
  }
 
  public void modelDirtyStateChanged(IStructuredModel model, boolean isDirty) {
    if (!isDirty && resource.isModified()) { // The XMLModel was saved
      resource.setModified(false);
      long stamp = WorkbenchResourceHelper.computeModificationStamp(resource);
      WorkbenchResourceHelper.setSynhronizationStamp(resource, stamp);
      IProject proj = WorkbenchResourceHelper.getProject(resource);
      ResourceSetWorkbenchEditSynchronizer synchronizer = (ResourceSetWorkbenchEditSynchronizer) ((ProjectResourceSet) WorkbenchResourceHelperBase.getResourceSet(proj)).getSynchronizer();
      IFile aFile = WorkbenchResourceHelper.getFile(resource);
      synchronizer.preSave(aFile, resource);
    }
    if (isDirty)
      resource.setModified(true);
  }

  public void modelReinitialized(IStructuredModel structuredModel) {
    // TODO Auto-generated method stub

  }

  public void modelResourceDeleted(IStructuredModel model) {
    // Do nothing
  }

  public void modelResourceMoved(IStructuredModel oldModel, IStructuredModel newModel) {
    // Do nothing
  }

  /**
   * This method is called just prior to being removed from the ResourceSet.
   * Ensure that all reference counts to the XMLModel are removed.
   */
  public void preDelete() {
    if (resource.isLoaded())
      deregisterFromXMLModel();
  }

  public void preUnload() {
    deregisterFromXMLModel();
  }

  public void processPostModelEvent(ModelLifecycleEvent event) {
    if (event.getType() == ModelLifecycleEvent.MODEL_REVERT)
      reverting = false;

  }

  public void processPreModelEvent(ModelLifecycleEvent event) {
    if (event.getType() == ModelLifecycleEvent.MODEL_REVERT)
      reverting = true;
     
    if (!isSaving) {
      if (event.getType() == ModelLifecycleEvent.MODEL_SAVED) {
        ResourceSetWorkbenchEditSynchronizer synchronizer = (ResourceSetWorkbenchEditSynchronizer) ((ProjectResourceSet) resource.getResourceSet()).getSynchronizer();
        IFile aFile = WorkbenchResourceHelper.getFile(resource);
        synchronizer.preSave(aFile, resource);
      }
    }
   
  }


  public void registerAsModelLifecycleListener() {
    this.xmlModel.addModelLifecycleListener(this);
  }

  /**
   * Insert the method's description here. Creation date: (9/7/2001 10:49:53
   * AM)
   */
  public void registerAsModelStateListener() {
    this.xmlModel.addModelStateListener(this);
  }

  public void releaseFromRead() {
    if (xmlModel != null)
      xmlModel.releaseFromRead();
  }

  public void releaseFromWrite() {
    if (xmlModel != null)
      xmlModel.releaseFromEdit();
  }

  public void removeDOMAdapter(Node aNode, EMF2DOMAdapter anAdapter) {
    ((IDOMNode) aNode).removeAdapter((EMF2DOMSSEAdapter) anAdapter);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.jem.internal.util.emf.xml.EMF2DOMRenderer#replaceDocumentType(java.lang.String,
   *      java.lang.String, java.lang.String)
   */
  public void replaceDocumentType(String docTypeName, String publicId, String systemId) {
    if (document == null)
      return;
    DocumentTypeImpl docType = (DocumentTypeImpl) document.getDoctype();
    if (docType == null)
      return;
    if (publicId == null && systemId == null)
      document.removeChild(docType);
    else {
      docType.setPublicId(publicId);
      docType.setSystemId(systemId);
    }
  }

  /**
   * @deprecated use batchModeStart and BatchModeEnd instead even if you do
   *             not use batchModelStart/End, you still need to use the
   *             try/finally pattern documented there.
   */

  public void setBatchMode(boolean isBatch) {

    // This is some extra processing for clients to know they may be using
    // incorrectly
    if (isBatch) {
      if (isBatchChanges) {
        Logger.log(Logger.INFO_DEBUG, "setBatch was set to true when it was already true. This can be an indication of invalid calling order"); //$NON-NLS-1$
      }
    }


    if (isBatch) {
      batchModeStart();
    }
    else {
      batchModeEnd();
    }
  }

  private void setRootNodeAdapterNotificationEnabled(boolean b) {
    EObject root = resource.getRootObject();
    if (root != null) {
      EMF2DOMAdapter adapter = (EMF2DOMAdapter) EcoreUtil.getExistingAdapter(root, EMF2DOMAdapter.ADAPTER_CLASS);
      if (adapter != null) {
        adapter.setNotificationEnabled(b);
        if (b)
          adapter.updateDOM();
      }
    }
  }

  /**
   * Return the DOM model for this resource.
   */
  public void setXMLModel(IDOMModel xmlModel) {
    deRegisterAsModelStateListener();
    deRegisterAsModelLifecycleListener();
    this.xmlModel = xmlModel;
    registerAsModelStateListener();
    registerAsModelLifecycleListener();
  }

  public void setXMLModelId(String id) {
    xmlModelId = id;
  }

  private void syncReferenceCounts(String id, boolean forWrite) {
    int editIndex = 0, readIndex = 0;
    if (forWrite)
      editIndex++;
    else
      readIndex++;
    int writeCount = resource.getWriteCount();
    int readCount = resource.getReadCount();
    for (int i = writeCount; i > editIndex; i--)
      modelManager.getExistingModelForEdit(id);
    for (int i = readCount; i > readIndex; i--)
      modelManager.getExistingModelForRead(id);
  }

  public boolean useStreamsForIO() {
    return false;
  }

  public boolean wasReverted() {
    return xmlModelReverted;
  }

  public void setResource(TranslatorResource resource) {
    super.setResource(resource);
    if (resource != null)
      resourceClass = resource.getClass();
  }
  public boolean isReverting() {
    return this.reverting;
  }


}
TOP

Related Classes of org.eclipse.wst.xml.core.internal.emf2xml.EMF2DOMSSERenderer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.