/******************************************************************************* * Copyright (c) 2010 Martin Schnabel <mb0@mb0.org>. * 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 ******************************************************************************/ package org.axdt.asdoc.parser.dita; import java.io.FileNotFoundException; import java.util.Collections; import java.util.List; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import org.axdt.asdoc.model.AsdocClass; import org.axdt.asdoc.model.AsdocConstructor; import org.axdt.asdoc.model.AsdocDefinition; import org.axdt.asdoc.model.AsdocElement; import org.axdt.asdoc.model.AsdocField; import org.axdt.asdoc.model.AsdocMember; import org.axdt.asdoc.model.AsdocOperation; import org.axdt.asdoc.model.AsdocPackage; import org.axdt.asdoc.model.AsdocProperty; import org.axdt.asdoc.model.AsdocType; import org.axdt.asdoc.parser.AbstractCollector; import org.axdt.asdoc.util.DitaUrlHelper; import org.axdt.avm.AvmEFactory; import org.axdt.avm.model.AvmDeclaredType; import org.axdt.avm.model.AvmDeclaredTypeReference; import org.axdt.avm.model.AvmType; import org.axdt.avm.model.AvmTypeReference; import org.axdt.avm.model.AvmVisibility; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.InternalEObject; import org.w3c.dom.Node; import com.google.common.collect.Lists; public class CollectTypes extends AbstractCollector { String typeDetailStr = "./apiClassifierDetail/apiClassifierDef"; XPathExpression typeDetail = xml.xexpr(typeDetailStr); XPathExpression typeIsInt = xml.xexpr(typeDetailStr + "/apiInterface"); XPathExpression typeIsDynamic = xml.xexpr(typeDetailStr + "/apiDynamic"); XPathExpression typeExtendsDetail = xml.xexpr("./apiBaseClassifier/text()"); XPathExpression typeImplementsDetail = xml .xexpr("./apiBaseInterface/text()"); XPathExpression valDetail = xml.xexpr("./apiValueDetail/apiValueDef"); XPathExpression valIsAccess = xml.xexpr("./apiValueAccess/@value"); XPathExpression valIsProp = xml.xexpr("./apiProperty"); XPathExpression valType = xml.xexpr("./apiType/@value|./apiValueClassifier/text()"); XPathExpression opDetail = xml .xexpr("./apiOperationDetail/apiOperationDef"); XPathExpression nameExpr = xml.xexpr("./apiName/text()"); XPathExpression accessExpr = xml.xexpr("./apiAccess/@value"); XPathExpression staticExpr = xml.xexpr("./apiStatic"); XPathExpression opReturn = xml.xexpr("./apiReturn/apiType/@value|./apiReturn/apiOperationClassifier/text()"); static final String nameType = "apiClassifier"; static final String nameValue = "apiValue"; static final String nameOperation = "apiOperation"; static final String nameConstructor = "apiConstructor"; public CollectTypes() { super(); } public boolean collectAllDetails(AsdocPackage pack) throws Exception { boolean result = false; if (pack.isTypeContentAvailable()||pack.isGlobalContentAvailable()) { if (null != collectDetails(pack)) result = true; } for (AsdocPackage child : pack.getPackages()) if (collectAllDetails(child)) result = true; return result; } public Node load(AsdocPackage pack) throws Exception { String uri = pack.getRoot().getBaseUri() + new DitaUrlHelper().packageUrl(pack); logger.info("loading : " + uri); return xml.load(uri); } public List<? extends AsdocDefinition> collectDetails(AsdocPackage pack) { try { Node node = load(pack).getFirstChild(); List<AsdocType> types = Lists.newArrayList(); List<AsdocMember> members = Lists.newArrayList(); // simple for loop is much faster for(Node child=node.getFirstChild(); child!=null; child=child.getNextSibling()) { String name = child.getNodeName(); if (name.equals(nameType)) { node2Type(child, types, false); } else { node2Member(child, members); } } if (!members.isEmpty()) { pack.setGlobalContentAvailable(true); Collections.sort(members, this); pack.getMembers().addAll(members); if (types.isEmpty()) return members; else { Collections.sort(types, this); pack.getTypes().addAll(types); List<AsdocDefinition> result = Lists.newArrayList(); result.addAll(types); result.addAll(members); return result; } } if (types.isEmpty()) return null; Collections.sort(types, this); pack.getTypes().addAll(types); return types; } catch (FileNotFoundException e) { if (pack.getRoot() != pack) logger.info("missing package file", e); } catch (Exception e) { logger.error("details", e); } return null; } public boolean collectAllTypes(AsdocPackage pack) throws Exception { boolean result = false; if (pack.isTypeContentAvailable()) { if (null != collectTypes(pack)) result = true; } for (AsdocPackage child : pack.getPackages()) if (collectAllTypes(child)) result = true; return result; } public List<AsdocType> collectTypes(AsdocPackage pack) throws Exception { try { Node node = load(pack).getFirstChild(); boolean hasGlobals = false; List<AsdocType> types = Lists.newArrayList(); for(Node child=node.getFirstChild(); child!=null; child=child.getNextSibling()) { String name = child.getNodeName(); if (name.equals(nameType)) { node2Type(child, types, false); } else if (name.equals(nameValue)||name.equals(nameOperation)) { hasGlobals = true; } } if (hasGlobals) pack.setGlobalContentAvailable(true); if (types.isEmpty()) return null; Collections.sort(types, this); pack.getTypes().addAll(types); return types; } catch (Exception e) { logger.error(e); } return null; } public boolean collectAllGlobals(AsdocPackage pack) throws Exception { boolean result = false; if (pack.isGlobalContentAvailable()) { if (null != collectGlobals(pack)) result = true; } for (AsdocPackage child : pack.getPackages()) if (collectAllGlobals(child)) result = true; return result; } public List<AsdocMember> collectGlobals(AsdocPackage pack) { try { Node node = load(pack).getFirstChild(); List<AsdocMember> members = Lists.newArrayList(); for(Node child=node.getFirstChild(); child!=null; child=child.getNextSibling()) { node2Member(child, members); } if (!members.isEmpty()) { pack.setGlobalContentAvailable(true); Collections.sort(members, this); pack.getMembers().addAll(members); return members; } } catch (Exception e) { logger.error(e); } return null; } public boolean collectAllMembers(AsdocPackage pack) { boolean result = false; if (pack.isTypeContentAvailable()) { if (collectPackageMembers(pack)) result = true; pack.setMemberContentParsed(true); } for (AsdocPackage child : pack.getPackages()) if (collectAllMembers(child)) result = true; return result; } public boolean collectPackageMembers(AsdocPackage pack) { try { Node node = load(pack).getFirstChild(); List<AsdocType> types = pack.getTypes(); for(Node child=node.getFirstChild(); child!=null; child=child.getNextSibling()) { if (nameType.equals(child.getNodeName())) node2Detail(child, types); } if (pack.eResource() != null) pack.eResource().setModified(true); return true; } catch (Exception e) { logger.error("allMembers", e); } return false; } public AsdocType collectMembers(AsdocType type) throws Exception { if (type.eContainer() instanceof AsdocPackage) return collectMembers((AsdocPackage) type.eContainer(), type); throw new Exception(type.getCanonicalName() + "has no package info"); } public AsdocType collectMembers(AsdocPackage pack, AsdocType type) throws Exception { try { Node node = load(pack).getFirstChild(); XPathExpression findTypeExpr = xml .xexpr("./apiClassifier[./apiName/text()='" + type.getName() + "']"); Node typeNode = xml.eval(findTypeExpr, node); parseType(type, typeNode); if (pack.eResource() != null) pack.eResource().setModified(true); return type; } catch (Exception e) { logger.error("members",e); } return null; } public AsdocType parseType(AsdocType type, Node node) throws Exception { Node detail = xml.eval(typeDetail, node); AvmTypeReference typeRef; if (type.isClass()) { typeRef = getTypeRef(xml.text(typeExtendsDetail, detail)); if (typeRef != null) ((AsdocClass) type).setExtendedClass(typeRef); for (Node in : xml.eIter(typeImplementsDetail, detail)) type.getExtendedInterfaces().add(getTypeRef(in.getNodeValue())); } else { typeRef = getTypeRef(xml.text(typeImplementsDetail, detail)); if (typeRef != null) type.getExtendedInterfaces().add(typeRef); } parseTypeMembers(type, node); type.setMemberContentParsed(true); return type; } public List<AsdocMember> parseTypeMembers(final AsdocType type, Node node) throws Exception { List<AsdocMember> members = Lists.newArrayList(); for(Node child=node.getFirstChild(); child!=null; child=child.getNextSibling()) { node2Member(child, members); } if (!members.isEmpty()) { Collections.sort(members, this); type.getMembers().addAll(members); return members; } return null; } public AvmTypeReference getTypeRef(String name) { if (name == null) return null; if ("".endsWith(name) || "*".equals(name)) return AvmEFactory.eINSTANCE.createAvmGenericReference(); if ("void".equals(name)) return AvmEFactory.eINSTANCE.createAvmVoidReference(); AvmDeclaredTypeReference ref = AvmEFactory.eINSTANCE .createAvmDeclaredTypeReference(); AvmType type = getTypeProxy(getProxyURI(name)); ref.setType(type); return ref; } public AvmType getTypeProxy(URI uri) { AvmDeclaredType proxy = asFactory.createAsdocClass(); ((InternalEObject) proxy).eSetProxyURI(uri); return proxy; } protected AsdocMember parseMember(Node node) throws XPathExpressionException { String name = node.getNodeName(); if (nameValue.equals(name)) return parseValue(node); if (nameOperation.equals(name)) return parseOperation(node); if (nameConstructor.equals(name)) return parseConstructor(node); return null; } protected AsdocMember parseValue(Node node) throws XPathExpressionException { AsdocField result = null; Node detail = xml.eval(valDetail, node); String accessType = xml.text(valIsAccess, detail); if (accessType != null) { AsdocProperty property = asFactory.createAsdocProperty(); if ("read".equals(accessType)) property.setReadonly(true); else if ("write".equals(accessType)) property.setWriteonly(true); result = property; } else { result = asFactory.createAsdocField(); result.setConstant(!xml.is(valIsProp, detail)); } String name = parseBasic(node, result); if (name == null || name.length() < 1 || name.charAt(0) == '-') return null; result.setName(name); result.setType(getTypeRef(xml.text(valType, detail))); result.setVisibility(getVisibility(xml.text(accessExpr, detail))); result.setStatic(xml.is(staticExpr, detail)); return result; } protected AvmVisibility getVisibility(String access) { AvmVisibility result = null; if ("public".equals(access)) { result = AvmVisibility.PUBLIC; } else if ("protected".equals(access)) { result = AvmVisibility.PROTECTED; } else if ("private".equals(access)) { result = AvmVisibility.PRIVATE; } return result; } protected AsdocMember parseOperation(Node node) throws XPathExpressionException { AsdocOperation result = asFactory.createAsdocOperation(); result.setName(parseBasic(node, result)); Node detail = xml.eval(opDetail, node); result.setReturnType(getTypeRef(xml.text(opReturn, detail))); result.setVisibility(getVisibility(xml.text(accessExpr, detail))); result.setStatic(xml.is(staticExpr, detail)); return result; } protected AsdocMember parseConstructor(Node node) throws XPathExpressionException { AsdocConstructor result = asFactory.createAsdocConstructor(); result.setName(parseBasic(node, result)); return result; } protected String parseBasic(Node node, AsdocElement elem) { String name = null; for(Node child=node.getFirstChild(); child!=null; child=child.getNextSibling()) { if (!child.hasChildNodes()) continue; String nodeName = child.getNodeName(); if ("shortdesc".equals(nodeName)) { String result = child.getFirstChild().getNodeValue(); if (result != null) elem.setAsdoc(result.trim()); } else if ("apiName".equals(nodeName)) { name = child.getFirstChild().getNodeValue(); } } return name; } protected void node2Member(Node node, List<AsdocMember> result) { try { AsdocMember member = parseMember(node); if (member != null) result.add(member); } catch (XPathExpressionException e) { logger.error("node2Member", e); } } protected AsdocType node2Type(Node node, List<AsdocType> result, boolean parseDetails) { try { AsdocType type; if (xml.is(typeIsInt, node)) { type = asFactory.createAsdocInterface(); } else { AsdocClass clss = asFactory.createAsdocClass(); clss.setDynamic(xml.is(typeIsDynamic, node)); type = clss; } String name = xml.attr(node, "id"); int index = name.lastIndexOf(':'); if (index > -1) name = name.substring(index + 1); type.setName(parseBasic(node, type)); if (parseDetails) parseType(type, node); result.add(type); return type; } catch (Exception e) { logger.error("collect type", e); } return null; } protected boolean node2Detail(Node node, List<AsdocType> types) { try { String name = xml.attr(node, "id"); int index = name.lastIndexOf(':'); if (index > -1) name = name.substring(index + 1); for (AsdocType type:types) { if (name.equals(type.getName())) { if (!type.isMemberContentParsed()) parseType(type, node); return true; } } } catch (Exception e) { logger.error(e); } return false; } }