// ============================================================================ // // Copyright (C) 2006-2016 Talend Inc. - www.talend.com // // This source code is available under agreement available at // %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt // // You should have received a copy of the agreement // along with this program; if not, write to Talend SA // 9 rue Pages 92150 Suresnes, France // // ============================================================================ package com.amalto.workbench.providers.datamodel; import java.io.FileInputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.regex.Pattern; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.emf.common.util.EList; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.Viewer; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.xsd.XSDAnnotation; import org.eclipse.xsd.XSDAttributeDeclaration; import org.eclipse.xsd.XSDAttributeGroupDefinition; import org.eclipse.xsd.XSDComplexTypeDefinition; import org.eclipse.xsd.XSDElementDeclaration; import org.eclipse.xsd.XSDIdentityConstraintDefinition; import org.eclipse.xsd.XSDInclude; import org.eclipse.xsd.XSDModelGroup; import org.eclipse.xsd.XSDNamedComponent; import org.eclipse.xsd.XSDParticle; import org.eclipse.xsd.XSDSchema; import org.eclipse.xsd.XSDSchemaContent; import org.eclipse.xsd.XSDSimpleTypeDefinition; import org.eclipse.xsd.XSDWildcard; import org.eclipse.xsd.impl.XSDSchemaImpl; import org.w3c.dom.Document; import org.w3c.dom.Element; import com.amalto.workbench.actions.XSDGetXPathAction; import com.amalto.workbench.models.TreeObject; import com.amalto.workbench.providers.ISchemaContentProvider; import com.amalto.workbench.utils.DataModelFilter; import com.amalto.workbench.utils.Util; public class SchemaTreeContentProvider implements ITreeContentProvider, ISchemaContentProvider { private static Log log = LogFactory.getLog(XSDGetXPathAction.class); protected XSDSchema xsdSchema; protected IWorkbenchPartSite site = null; protected TreeObject treeObj; public SchemaTreeContentProvider(IWorkbenchPartSite site, XSDSchema invisibleRoot) { this.site = site; this.xsdSchema = invisibleRoot; } public void inputChanged(Viewer v, Object oldInput, Object newInput) { } public void dispose() { } public Object[] getElements(Object parent) { if (parent.equals(site)) { return getChildren(xsdSchema); } return getChildren(parent); } public Object getParent(Object child) { return null; } public void setFilter(DataModelFilter filter) { } public Object[] getChildren(Object parent) { if (parent == null) { return new Object[0]; } return findChildren(parent); } protected Object[] findChildren(Object parent) { if (parent instanceof XSDSchema) { return getXSDSchemaChildren((XSDSchema) parent); } if (parent instanceof XSDAttributeGroupDefinition) { return getXSDAttributeGroupDefinitionChildren((XSDAttributeGroupDefinition) parent); } if (parent instanceof XSDParticle) { return getXSDParticleChildren((XSDParticle) parent); } if (parent instanceof XSDModelGroup) { return getXSDModelGroupChildren((XSDModelGroup) parent); } if (parent instanceof XSDSimpleTypeDefinition) { return getXSDSimpleTypeDefinitionChildren((XSDSimpleTypeDefinition) parent); } if (parent instanceof XSDElementDeclaration) { return getXSDElementDeclarationChildren((XSDElementDeclaration) parent); } if (parent instanceof XSDIdentityConstraintDefinition) { return getXSDIdentityConstraintDefinitionChildren((XSDIdentityConstraintDefinition) parent); } if (parent instanceof XSDAnnotation) { return getXSDAnnotationChildren((XSDAnnotation) parent); } // appinfos if (parent instanceof Element) { return new Object[0]; } return new Object[0]; } public boolean hasChildren(Object parent) { return getChildren(parent).length > 0; } public XSDSchema getXsdSchema() { return xsdSchema; } public void setXsdSchema(String xsd) { try { xsdSchema = Util.createXsdSchema(xsd, treeObj); } catch (Exception e) { log.error(e.getMessage(), e); } } public void setXsdSchema(XSDSchema xsdSchema) { this.xsdSchema = xsdSchema; } public String getXSDSchemaAsString() throws Exception { if (xsdSchema == null) { return "";//$NON-NLS-1$ } Document document = xsdSchema.getDocument(); String schema = Util.nodeToString(document); // FIXES a bug in the XSD library that puts nillable attributes in // elements which are ref // That is illegal according to W3C ยง3.3.3 / 2.2 (and Xerces) Pattern p = Pattern.compile("(<([a-z]+:)?element.*?)nillable=['|\"].*?['|\"](.*?ref=.*?>)");//$NON-NLS-1$ schema = p.matcher(schema).replaceAll("$1 $3");//$NON-NLS-1$ return schema; } public XSDSchema createSchema(String location){ InputStream stream = null; try { stream = new FileInputStream(location); DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); documentBuilderFactory.setNamespaceAware(true); documentBuilderFactory.setValidating(false); DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); Document document = documentBuilder.parse(stream); return XSDSchemaImpl.createSchema(document.getDocumentElement()); } catch (Exception e) { log.error(e.getMessage()); return null; }finally{ IOUtils.closeQuietly(stream); } } protected void addElementDeclarationFromSchema(XSDSchema schema,Collection<XSDElementDeclaration> declarations){ EList<XSDElementDeclaration> elementDeclarations = schema.getElementDeclarations(); for(XSDElementDeclaration declaration:elementDeclarations) { if(declaration.eContainer().equals(schema)) { declarations.add(declaration); } } } protected Object[] getXSDSchemaChildren(XSDSchema schema) { List<XSDElementDeclaration> declarations = new ArrayList<XSDElementDeclaration>(); List<Object> attributeDeclarations = new ArrayList<Object>(); if (null != xsdSchema) { for (XSDSchemaContent cnt : xsdSchema.getContents()) { if (cnt instanceof XSDInclude) { XSDInclude incu = (XSDInclude) cnt; String schemaLocation = incu.getSchemaLocation(); XSDSchema schemaInc = createSchema(schemaLocation); addElementDeclarationFromSchema(schemaInc, declarations); } else if (cnt instanceof XSDAttributeDeclaration) { XSDAttributeDeclaration attriDec = (XSDAttributeDeclaration) cnt; attributeDeclarations.add(attriDec); } } } addElementDeclarationFromSchema(schema, declarations); Object[] schemaChildren = Util.filterOutDuplicatedElems(declarations .toArray(new XSDNamedComponent[declarations.size()])); attributeDeclarations.addAll(Arrays.asList(schemaChildren)); return attributeDeclarations.toArray(); } protected Object[] getXSDAttributeGroupDefinitionChildren(XSDAttributeGroupDefinition parent) { XSDAttributeGroupDefinition attributeGroupDefinition = parent; if (attributeGroupDefinition.getContents().size() == 0) { attributeGroupDefinition = attributeGroupDefinition.getResolvedAttributeGroupDefinition(); } return attributeGroupDefinition.getContents().toArray(new Object[attributeGroupDefinition.getContents().size()]); } protected Object[] getXSDParticleChildren(XSDParticle particle) { if (particle.getTerm() instanceof XSDElementDeclaration) { return getXSDElementDeclarationChildren((XSDElementDeclaration) particle.getTerm()); } if (particle.getTerm() instanceof XSDModelGroup) { return getXSDModelGroupChildren((XSDModelGroup) particle.getTerm()); } if (particle.getTerm() instanceof XSDWildcard) { } return new Object[] {}; } protected Object[] getXSDModelGroupChildren(XSDModelGroup parent) { return parent.getContents().toArray(new Object[parent.getContents().size()]); } protected Object[] getXSDSimpleTypeDefinitionChildren(XSDSimpleTypeDefinition parent) { Object[] result = null; switch (parent.getVariety()) { case ATOMIC_LITERAL: result = getXSDSimpleTypeDefinitionChildren_ATOMIC(parent); break; case LIST_LITERAL: result = getXSDSimpleTypeDefinitionChildren_LIST(parent); break; case UNION_LITERAL: result = getXSDSimpleTypeDefinitionChildren_UNION(parent); break; default: result = new Object[0]; } return result; } private Object[] getXSDSimpleTypeDefinitionChildren_UNION(XSDSimpleTypeDefinition parent) { return parent.getMemberTypeDefinitions().toArray(new XSDSimpleTypeDefinition[parent.getMemberTypeDefinitions().size()]); } private Object[] getXSDSimpleTypeDefinitionChildren_LIST(XSDSimpleTypeDefinition parent) { // FIXME: How do we indicate it is a LIST? return new XSDSimpleTypeDefinition[] { parent.getBaseTypeDefinition() }; } private Object[] getXSDSimpleTypeDefinitionChildren_ATOMIC(XSDSimpleTypeDefinition parent) { ArrayList<Object> list = new ArrayList<Object>(); // add Base Type if not a pre-defined type if (parent != null && parent.getSchema() != null && parent.getSchema().getSchemaForSchema() != null) { if (!parent.getSchema().getSchemaForSchema().getTypeDefinitions().contains(parent)) { list.add(parent.getBaseTypeDefinition()); } } if (!Util.isBuildInType(parent)) { list.addAll(parent.getFacetContents()); } return list.toArray(new Object[list.size()]); } protected Object[] getXSDIdentityConstraintDefinitionChildren(XSDIdentityConstraintDefinition parent) { ArrayList<Object> list = new ArrayList<Object>(); list.add(parent.getSelector()); list.addAll(parent.getFields()); return list.toArray(new Object[list.size()]); } protected Object[] getXSDAnnotationChildren(XSDAnnotation parent) { ArrayList<Object> list = new ArrayList<Object>(); list.addAll(parent.getUserInformation()); list.addAll(parent.getApplicationInformation()); return list.toArray(new Object[list.size()]); } protected void addEleDeclarationAnn2List(List<Object> list, XSDElementDeclaration element) { if (element.getAnnotation() != null) { list.add(element.getAnnotation()); } } protected Object[] getXSDElementDeclarationChildren_TypeDef(XSDElementDeclaration parent) { ArrayList<Object> list = new ArrayList<Object>(); if (parent.getTypeDefinition() == null) { return new Object[0]; // elements with not type declaration } // handle extensions and restrictions directly if (parent.getTypeDefinition() instanceof XSDComplexTypeDefinition) { list.addAll(Util.getComplexTypeDefinitionChildren((XSDComplexTypeDefinition) parent.getTypeDefinition(), true)); } else { list.addAll(Util.getSimpleTypeDefinitionChildren((XSDSimpleTypeDefinition)parent.getTypeDefinition())); } return list.toArray(); } protected XSDIdentityConstraintDefinition[] getXSDElementDeclarationChildren_IDs(XSDElementDeclaration parent) { return parent.getIdentityConstraintDefinitions().toArray(new XSDIdentityConstraintDefinition[0]); } protected Object[] getXSDElementDeclarationChildren(XSDElementDeclaration parent) { // abstract elements do not have children if (parent.isAbstract()) { return new Object[0]; } ArrayList<Object> list = new ArrayList<Object>(); list.addAll(Arrays.asList(getXSDElementDeclarationChildren_TypeDef(parent))); // the keys list.addAll(Arrays.asList(getXSDElementDeclarationChildren_IDs(parent))); // the annotations addEleDeclarationAnn2List(list, parent); return list.toArray(new Object[list.size()]); } }