/******************************************************************************* * Copyright (c) 2005, 2006 committers of openArchitectureWare 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: * committers of openArchitectureWare - initial API and implementation *******************************************************************************/ package org.eclipse.emf.mwe.internal.core.ast.parser; import java.io.InputStream; import java.util.Arrays; import java.util.HashSet; import java.util.Set; import java.util.Stack; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.emf.mwe.core.issues.Issues; import org.eclipse.emf.mwe.internal.core.ast.AbstractASTBase; import org.eclipse.emf.mwe.internal.core.ast.ComponentAST; import org.eclipse.emf.mwe.internal.core.ast.DeclaredPropertyAST; import org.eclipse.emf.mwe.internal.core.ast.DeclaredPropertyFileAST; import org.eclipse.emf.mwe.internal.core.ast.InclusionAST; import org.eclipse.emf.mwe.internal.core.ast.ReferenceAST; import org.eclipse.emf.mwe.internal.core.ast.SimpleParamAST; import org.xml.sax.Attributes; import org.xml.sax.Locator; import org.xml.sax.helpers.DefaultHandler; public class WorkflowParser extends DefaultHandler { private static final Log log = LogFactory.getLog(WorkflowParser.class); // reserved element names public final static String PROPERTY = "property"; // reserver attribute names public final static String CLASS = "class"; // components public final static String FILE = "file"; // include public final static String ID = "id"; // components public final static String IDREF = "idRef"; // references public final static String VALUE = "value"; // property, simple params public final static String NAME = "name"; // property private static final String INHERITALL = "inheritAll"; private final Stack<Object> eleStack = new Stack<Object>(); private AbstractASTBase root = null; private org.xml.sax.Locator locator = null; private String resource = "unknown"; private Issues issues = null; public WorkflowParser() { } public AbstractASTBase parse(final InputStream in, final String resourceName, final Issues issues) { resource = resourceName; this.issues = issues; try { final SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); parser.parse(in, this); } catch (final Exception e) { root = null; log.error(e.getMessage(), e); issues.addError(e.getMessage(), resourceName); } return root; } @Override public void setDocumentLocator(final Locator locator) { this.locator = locator; } @Override public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) { if (PROPERTY.equals(qName)) { final AbstractASTBase prop = handleProperty(qName, attributes); connectAndPush(prop); } else { final AbstractASTBase ele = handleComp(qName, attributes); connectAndPush(ele); } } private void connectAndPush(final AbstractASTBase prop) { if (eleStack.isEmpty()) { eleStack.push(prop); } else if (eleStack.peek() instanceof ComponentAST) { ((ComponentAST) eleStack.peek()).getChildren().add(prop); eleStack.push(prop); } else { issues.addError("The element " + eleStack.peek() + " cannot contain any child elements!", prop); eleStack.push("DUMMY"); } } protected AbstractASTBase handleComp(final String name, final Attributes attributes) { if (attributes.getValue(FILE) != null) { final boolean inheritAll = attributes.getValue(INHERITALL) != null; final InclusionAST c = new InclusionAST(getLocation(), name, attributes.getValue(FILE), attributes .getValue(ID), inheritAll); if (attributes.getValue(CLASS) != null) { issues.addError("Attribute 'class' not allowed for inclusions : " + PROPERTY, c); } for (int i = 0; i < attributes.getLength(); i++) { final String temp = attributes.getQName(i); if (!"".equals(temp) && !(FILE.equals(temp) || ID.equals(temp))) { c.addChild(new SimpleParamAST(getLocation(), temp, attributes.getValue(temp))); } } return c; } else if (attributes.getValue(IDREF) != null) { validateAttributes("reference " + name, attributes, new String[] { IDREF }, new String[0]); return new ReferenceAST(getLocation(), name, attributes.getValue(IDREF)); } else if ((attributes.getValue(VALUE) != null) && (attributes.getValue(NAME) == null)) { validateAttributes("simpleparam " + name, attributes, new String[] { VALUE }, new String[] {}); return new SimpleParamAST(getLocation(), name, attributes.getValue(VALUE)); } else { final ComponentAST result = new ComponentAST(getLocation(), name, attributes.getValue(CLASS), attributes .getValue(ID)); for (int i = 0; i < attributes.getLength(); i++) { final String temp = attributes.getQName(i); if (!"".equals(temp) && !(CLASS.equals(temp) || ID.equals(temp))) { result.addChild(new SimpleParamAST(getLocation(), temp, attributes.getValue(temp))); } } return result; } } protected AbstractASTBase handleProperty(final String localName, final Attributes attributes) { if (attributes.getValue(NAME) != null) { validateAttributes(localName, attributes, new String[] { NAME }, new String[] { VALUE }); return new DeclaredPropertyAST(getLocation(), attributes.getValue(NAME), attributes.getValue(VALUE)); } else if (attributes.getValue(FILE) != null) { validateAttributes(localName, attributes, new String[] { FILE }, new String[0]); return new DeclaredPropertyFileAST(getLocation(), attributes.getValue(FILE)); } else { issues.addError("Either 'name' or 'file' attribute is mandatory for element " + PROPERTY, getLocation()); return new DeclaredPropertyAST(getLocation(), "__UNKNOWN__"); } } private void validateAttributes(final String eleName, final Attributes attributes, final String[] mandatory, final String[] optional) { final Set<String> mandatorySet = new HashSet<String>(Arrays.asList(mandatory)); final Set<String> optionalSet = new HashSet<String>(Arrays.asList(optional)); final Set<String> mandatoryFound = new HashSet<String>(); for (int i = 0; i < attributes.getLength(); i++) { final String name = attributes.getQName(i); if ((name != null) && !name.trim().equals("")) { if (!(mandatorySet.contains(name) || optionalSet.contains(name))) { issues.addError("Unknown attribute " + name + " for element " + eleName, getLocation()); } } if (mandatorySet.contains(name)) { mandatoryFound.add(name); } } mandatorySet.removeAll(mandatoryFound); if (!mandatorySet.isEmpty()) { for (final String name : mandatorySet) { issues.addError("Attribute " + name + " is mandatory for element " + eleName, getLocation()); } } } private Location getLocation() { return new Location(locator.getLineNumber(), locator.getColumnNumber(), resource); } @Override public void endElement(final String uri, final String name, final String qName) { root = (AbstractASTBase) eleStack.pop(); } }