/******************************************************************************* * Copyright (c) 2010 SAP AG. * 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: * Emil Simeonov - initial API and implementation. * Dimitar Donchev - initial API and implementation. * Dimitar Tenev - initial API and implementation. * Nevena Manova - initial API and implementation. * Georgi Konstantinov - initial API and implementation. * Stanislav Nichev - initial API and implementation. *******************************************************************************/ package org.eclipse.wst.sse.sieditor.model.reconcile.adapters; import java.util.List; import org.eclipse.emf.ecore.EObject; import org.eclipse.wst.sse.core.internal.provisional.INodeNotifier; import org.eclipse.wst.wsdl.Message; import org.eclipse.wst.wsdl.Types; import org.eclipse.wst.wsdl.XSDSchemaExtensibilityElement; import org.eclipse.xsd.XSDConcreteComponent; import org.eclipse.xsd.XSDSchema; import org.eclipse.xsd.XSDSchemaContent; import org.eclipse.xsd.XSDTypeDefinition; import org.eclipse.xsd.impl.XSDImportImpl; import org.eclipse.xsd.util.XSDConstants; import org.w3c.dom.Element; import org.eclipse.wst.sse.sieditor.model.reconcile.adapters.componentsource.IConcreteComponentSource; import org.eclipse.wst.sse.sieditor.model.reconcile.adapters.utils.ConcreteComponentsCacheUtils; /** * Subclass of the {@link AbstractModelReconcileAdapter}. This adapter is * responsible for the fixing of problems caused by DOM element changes - * removal, addition. * */ public class ElementsReconcileAdapter extends AbstractModelReconcileAdapter { public ElementsReconcileAdapter(final IConcreteComponentSource concreteComponentSource) { super(concreteComponentSource); } @Override protected void processNotifyChanged(final INodeNotifier notifier, final int eventType, final Object changedFeature, final Object oldValue, final Object newValue, final int pos) { processChangeOfSchemaContent(notifier, changedFeature, eventType, INodeNotifier.REMOVE); processChangeOfSchemaContent(notifier, newValue, eventType, INodeNotifier.ADD); processMessagePartRemoved(notifier, changedFeature, newValue, eventType); processChangeOfTypesNamespace(notifier, newValue, eventType, INodeNotifier.ADD); processChangeOfTypesNamespace(notifier, oldValue, eventType, INodeNotifier.REMOVE); processChangeOfXsdInclude(notifier, newValue, eventType, INodeNotifier.ADD); processChangeOfXsdInclude(notifier, oldValue, eventType, INodeNotifier.REMOVE); processChangeOfXsdImport(notifier, newValue, eventType, INodeNotifier.ADD); processChangeOfXsdImport(notifier, oldValue, eventType, INodeNotifier.REMOVE); processChangeOfAttribute(notifier, newValue, eventType, INodeNotifier.ADD); processChangeOfAttribute(notifier, oldValue, eventType, INodeNotifier.REMOVE); } private void processChangeOfSchemaContent(final Object notifier, final Object changedFeature, final int eventType, final int expectedEventType) { if (!(changedFeature instanceof Element) || !(notifier instanceof Element) || eventType != expectedEventType) { return; } final EObject containerObject = concreteComponentSource.getConcreteComponentFor((Element) notifier); if (!(containerObject instanceof XSDSchema) && !(containerObject instanceof XSDSchemaExtensibilityElement)) { return; } final String nodeName = ((Element) changedFeature).getNodeName(); final String nodeSimpleName = nodeName.substring(nodeName.indexOf(':') + 1); if (XSDConstants.ELEMENT_ELEMENT_TAG.equals(nodeSimpleName) || XSDConstants.SIMPLETYPE_ELEMENT_TAG.equals(nodeSimpleName) || XSDConstants.COMPLEXTYPE_ELEMENT_TAG.equals(nodeSimpleName) || XSDConstants.ATTRIBUTE_ELEMENT_TAG.equals(nodeSimpleName) || XSDConstants.ATTRIBUTEGROUP_ELEMENT_TAG.equals(nodeSimpleName) || XSDConstants.GROUP_ELEMENT_TAG.equals(nodeSimpleName)) { final XSDSchema schema = containerObject instanceof XSDSchema ? (XSDSchema) containerObject : ((XSDSchemaExtensibilityElement) containerObject).getSchema(); schema.elementChanged(schema.getElement()); getModelReconcileRegistry().setNeedsReconciling(true); getModelReconcileRegistry().addChangedSchema(schema); } } private void processMessagePartRemoved(final Object notifier, final Object changedFeature, final Object newValue, final int eventType) { if (!(changedFeature instanceof Element) || !(notifier instanceof Element)) { return; } final EObject containerObject = concreteComponentSource.getConcreteComponentFor((Element) notifier); if (containerObject instanceof Message && newValue == null) { getModelReconcileRegistry().setNeedsReconciling(true); } } @SuppressWarnings("unchecked") private void processChangeOfTypesNamespace(final INodeNotifier notifier, final Object schemaElementObject, final int eventType, final int expectedEventType) { if (!(notifier instanceof Element) || !(schemaElementObject instanceof Element) || eventType != expectedEventType) { return; } final Element schemaElement = (Element) schemaElementObject; if (!(XSDConstants.SCHEMA_ELEMENT_TAG.equals(schemaElement.getLocalName().substring( schemaElement.getLocalName().indexOf(':') + 1)))) { return; } final EObject eNotifier = concreteComponentSource.getConcreteComponentFor((Element) notifier); if (!(eNotifier instanceof Types)) { return; } final Types eTypes = (Types) eNotifier; eTypes.elementChanged(eTypes.getElement()); final List<XSDSchema> xsdSchemas = eTypes.getSchemas(); for (final XSDSchema xsdSchema : xsdSchemas) { cacheUtils().clearConcreteComponentsCacheForSchema(xsdSchema, eTypes); updateReferences(xsdSchema, eTypes, schemaElement); xsdSchema.elementChanged(xsdSchema.getElement()); } getModelReconcileRegistry().setNeedsReconciling(true); } private void processChangeOfXsdInclude(final INodeNotifier notifier, final Object includeValue, final int eventType, final int expectedEventType) { final String schemaDirectiveTag = XSDConstants.INCLUDE_ELEMENT_TAG; processChangeOfXsdSchemaDirective(notifier, includeValue, eventType, expectedEventType, schemaDirectiveTag); } private void processChangeOfXsdImport(final INodeNotifier notifier, final Object importValue, final int eventType, final int expectedEventType) { final String schemaDirectiveTag = XSDConstants.IMPORT_ELEMENT_TAG; final XSDSchema xsdSchema = processChangeOfXsdSchemaDirective(notifier, importValue, eventType, expectedEventType, schemaDirectiveTag); if (xsdSchema == null) { return; } if (eventType == INodeNotifier.REMOVE) { cacheUtils().clearConcreteComponentsCacheForSchema(xsdSchema, null); } } private XSDSchema processChangeOfXsdSchemaDirective(final INodeNotifier notifier, final Object includeValue, final int eventType, final int expectedEventType, final String schemaDirectiveTag) { if (!(notifier instanceof Element) || !(includeValue instanceof Element) || eventType != expectedEventType) { return null; } final EObject eContainerObject = concreteComponentSource.getConcreteComponentFor((Element) notifier); XSDSchema xsdSchema = null; if (eContainerObject instanceof XSDSchema) { xsdSchema = (XSDSchema) eContainerObject; } else if (eContainerObject instanceof XSDSchemaExtensibilityElement) { xsdSchema = ((XSDSchemaExtensibilityElement) eContainerObject).getSchema(); } else { return null; } final String nodeName = ((Element) includeValue).getNodeName(); final String simpleNodeName = nodeName.substring(nodeName.indexOf(':') + 1); if (!schemaDirectiveTag.equals(simpleNodeName)) { return null; } xsdSchema.elementChanged(xsdSchema.getElement()); getModelReconcileRegistry().setNeedsReconciling(true); getModelReconcileRegistry().addChangedSchema(xsdSchema); return xsdSchema; } private void processChangeOfAttribute(final INodeNotifier notifier, final Object changedElement, final int eventType, final int expectedEvent) { if (eventType != expectedEvent || !(notifier instanceof Element) || !(changedElement instanceof Element) || !XSDConstants.ATTRIBUTE_ELEMENT_TAG.equals(((Element) changedElement).getNodeName().substring( ((Element) changedElement).getNodeName().indexOf(':') + 1))) { return; } final EObject eObject = concreteComponentSource.getConcreteComponentFor((Element) notifier); if (eObject instanceof XSDTypeDefinition) { final XSDTypeDefinition xsdTypeDefinition = (XSDTypeDefinition) eObject; if (xsdTypeDefinition.getName() == null) { final XSDConcreteComponent container = (XSDConcreteComponent) xsdTypeDefinition.eContainer(); container.elementChanged(container.getElement()); } } getModelReconcileRegistry().setNeedsReconciling(true); } private void updateReferences(final XSDSchema xsdSchema, final Types eTypes, final Element oldValue) { for (final XSDSchemaContent schemaContent : xsdSchema.getContents()) { if (!(schemaContent instanceof XSDImportImpl)) { continue; } final XSDImportImpl xsdImport = (XSDImportImpl) schemaContent; xsdImport.elementChanged(xsdImport.getElement()); XSDSchema resolvedSchema = xsdImport.getResolvedSchema(); if (resolvedSchema == null || resolvedSchema.eContainer() instanceof XSDSchemaExtensibilityElement && resolvedSchema.eContainer().eContainer() == null) { xsdImport.reset(); resolvedSchema = xsdImport.importSchema(); } if (xsdImport.getSchemaLocation() == null && (!eTypes.getSchemas().contains(resolvedSchema) || resolvedSchema.getElement() == oldValue)) { xsdImport.setResolvedSchema(null); } } } // ========================================================= // helpers // ========================================================= private ConcreteComponentsCacheUtils cacheUtils() { return ConcreteComponentsCacheUtils.instance(); } }