blob: 17180ca7bf442ace93d1c96fa4fd6277225ed92b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2006 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.dtd.core.internal.contentmodel;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.ibm.icu.util.StringTokenizer;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.notify.impl.AdapterFactoryImpl;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.wst.dtd.core.internal.emf.DTDAnyContent;
import org.eclipse.wst.dtd.core.internal.emf.DTDAttribute;
import org.eclipse.wst.dtd.core.internal.emf.DTDBasicType;
import org.eclipse.wst.dtd.core.internal.emf.DTDBasicTypeKind;
import org.eclipse.wst.dtd.core.internal.emf.DTDDefaultKind;
import org.eclipse.wst.dtd.core.internal.emf.DTDElement;
import org.eclipse.wst.dtd.core.internal.emf.DTDElementContent;
import org.eclipse.wst.dtd.core.internal.emf.DTDElementReferenceContent;
import org.eclipse.wst.dtd.core.internal.emf.DTDEmptyContent;
import org.eclipse.wst.dtd.core.internal.emf.DTDEntity;
import org.eclipse.wst.dtd.core.internal.emf.DTDEnumerationType;
import org.eclipse.wst.dtd.core.internal.emf.DTDFile;
import org.eclipse.wst.dtd.core.internal.emf.DTDGroupContent;
import org.eclipse.wst.dtd.core.internal.emf.DTDGroupKind;
import org.eclipse.wst.dtd.core.internal.emf.DTDInternalEntity;
import org.eclipse.wst.dtd.core.internal.emf.DTDOccurrenceType;
import org.eclipse.wst.dtd.core.internal.emf.DTDPCDataContent;
import org.eclipse.wst.dtd.core.internal.emf.DTDRepeatableContent;
import org.eclipse.wst.dtd.core.internal.emf.DTDType;
import org.eclipse.wst.dtd.core.internal.emf.impl.DTDBasicTypeImpl;
import org.eclipse.wst.dtd.core.internal.emf.impl.DTDPackageImpl;
import org.eclipse.wst.dtd.core.internal.emf.util.DTDMetrics;
import org.eclipse.wst.dtd.core.internal.emf.util.DTDUtil;
import org.eclipse.wst.xml.core.internal.contentmodel.CMAttributeDeclaration;
import org.eclipse.wst.xml.core.internal.contentmodel.CMContent;
import org.eclipse.wst.xml.core.internal.contentmodel.CMDataType;
import org.eclipse.wst.xml.core.internal.contentmodel.CMDocument;
import org.eclipse.wst.xml.core.internal.contentmodel.CMDocumentation;
import org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration;
import org.eclipse.wst.xml.core.internal.contentmodel.CMEntityDeclaration;
import org.eclipse.wst.xml.core.internal.contentmodel.CMGroup;
import org.eclipse.wst.xml.core.internal.contentmodel.CMNamedNodeMap;
import org.eclipse.wst.xml.core.internal.contentmodel.CMNamespace;
import org.eclipse.wst.xml.core.internal.contentmodel.CMNode;
import org.eclipse.wst.xml.core.internal.contentmodel.CMNodeList;
import org.eclipse.wst.xml.core.internal.contentmodel.annotation.AnnotationMap;
import org.eclipse.wst.xml.core.internal.contentmodel.basic.CMDataTypeImpl;
import org.eclipse.wst.xml.core.internal.contentmodel.basic.CMEntityDeclarationImpl;
import org.eclipse.wst.xml.core.internal.contentmodel.basic.CMNamedNodeMapImpl;
import org.eclipse.wst.xml.core.internal.contentmodel.basic.CMNodeListImpl;
import org.eclipse.wst.xml.core.internal.contentmodel.util.CMDescriptionBuilder;
public class DTDImpl {
static {
// Call init on the DTD package to avoid strange initialization bugs
//
DTDPackageImpl.init();
}
protected static DTDAdapterFactoryImpl dtdAdapterFactoryImpl = new DTDAdapterFactoryImpl();
protected static CMDataTypeInfoTable cmDataTypeInfoTable = new CMDataTypeInfoTable();
public static CMDocument buildCMDocument(String uri) {
DTDFile dtdFile = buildDTDModel(uri);
CMDocument cmDocument = (CMDocument) getAdapter(dtdFile);
return cmDocument;
}
public static DTDFile buildDTDModel(String uri) {
DTDUtil dtdUtil = new DTDUtil();
dtdUtil.setexpandEntityReferences(true);
dtdUtil.parse(new ResourceSetImpl(), uri);
return dtdUtil.getDTDFile();
}
public static CMDocument buildCMDocument(DTDFile dtdFile) {
return (CMDocument) getAdapter(dtdFile);
}
public static CMNode getAdapter(Notifier o) {
return (CMNode) dtdAdapterFactoryImpl.adapt(o);
}
public static int getMinOccurHelper(DTDRepeatableContent content) {
int occurence = content.getOccurrence().getValue();
boolean isOptional = (occurence == DTDOccurrenceType.OPTIONAL || occurence == DTDOccurrenceType.ZERO_OR_MORE);
return isOptional ? 0 : 1;
}
public static int getMaxOccurHelper(DTDRepeatableContent content) {
int occurence = content.getOccurrence().getValue();
boolean isMulti = (occurence == DTDOccurrenceType.ONE_OR_MORE || occurence == DTDOccurrenceType.ZERO_OR_MORE);
return isMulti ? -1 : 1;
}
public static class DTDAdapterFactoryImpl extends AdapterFactoryImpl {
public Adapter createAdapter(Notifier target) {
Adapter result = null;
if (target != null) {
if (target instanceof DTDAttribute) {
result = new DTDAttributeAdapter((DTDAttribute) target);
}
else if (target instanceof DTDElement) {
result = new DTDElementAdapter((DTDElement) target);
}
else if (target instanceof DTDElementReferenceContent) {
result = new DTDElementReferenceContentAdapter((DTDElementReferenceContent) target);
}
else if (target instanceof DTDFile) {
result = new DTDFileAdapter((DTDFile) target);
}
else if (target instanceof DTDGroupContent) {
result = new DTDGroupContentAdapter((DTDGroupContent) target);
}
else if (target instanceof DTDEntity) {
result = new DTDEntityAdapter((DTDEntity) target);
}
}
return result;
}
public Adapter adapt(Notifier target) {
return adapt(target, this);
}
}
/**
* DTDBaseAdapter
*/
public static abstract class DTDBaseAdapter extends CMNodeImpl {
public String getNodeName() {
return ""; //$NON-NLS-1$
}
public boolean isAdapterForType(Object type) {
return type == dtdAdapterFactoryImpl;
}
public Object getProperty(String propertyName) {
Object result = null;
if (propertyName.equals("CMDocument")) { //$NON-NLS-1$
result = getCMDocument();
}
else if (propertyName.equals(PROPERTY_DOCUMENTATION)) {
result = getDocumentation();
}
else if (propertyName.equals(PROPERTY_DEFINITION_INFO)) {
result = getDefinitionInfo();
}
else if (propertyName.equals(PROPERTY_DEFINITION)) {
result = getDefinition();
}
else if (propertyName.equals(PROPERTY_MOF_NOTIFIER)) {
result = getKey();
}
else if (propertyName.equals("spec")) { //$NON-NLS-1$
result = getSpec();
}
else {
result = super.getProperty(propertyName);
if (result == null) {
CMDocument cmDocument = getCMDocument();
if (cmDocument instanceof DTDFileAdapter) {
AnnotationMap map = ((DTDFileAdapter) cmDocument).annotationMap;
if (map != null) {
String spec = getSpec();
if (spec != null) {
result = map.getProperty(getSpec(), propertyName);
}
}
if (result == null) {
Map globalPropertyMap = ((DTDFileAdapter) cmDocument).globalPropertyMap;
result = globalPropertyMap.get(propertyName);
}
}
}
}
return result;
}
public CMDocument getCMDocument() {
return null;
}
protected CMNodeList getDocumentation() {
return new CMNodeListImpl();
}
public String getDefinitionInfo() {
return null;
}
public CMNode getDefinition() {
return null;
}
public String getSpec() {
return getNodeName();
}
}
/**
* DTDAttributeAdapter
*/
public static class DTDAttributeAdapter extends DTDBaseAdapter implements CMAttributeDeclaration {
protected DTDAttribute attribute;
protected CMDataType dataType;
public DTDAttributeAdapter(DTDAttribute attribute) {
this.attribute = attribute;
dataType = new DataTypeImpl();
}
public Object getKey() {
return attribute;
}
public String getSpec() {
return attribute.getDTDElement().getName() + "/@" + attribute.getName(); //$NON-NLS-1$
}
public int getNodeType() {
return ATTRIBUTE_DECLARATION;
}
public String getNodeName() {
return attribute.getName();
}
public String getAttrName() {
return attribute.getName();
}
public CMDataType getAttrType() {
return dataType;
}
public String getDefaultValue() {
return attribute.getDefaultValueString();
}
public Enumeration getEnumAttr() {
return Collections.enumeration(attribute.getEnumeratedValues());
}
public int getUsage() {
int usage = OPTIONAL;
switch (attribute.getDefaultKind().getValue()) {
case DTDDefaultKind.REQUIRED : {
usage = REQUIRED;
break;
}
case DTDDefaultKind.FIXED : {
usage = FIXED;
break;
}
}
return usage;
}
public CMDocument getCMDocument() {
DTDFile dtdFile = attribute.getDTDElement().getDTDFile();
return dtdFile != null ? (CMDocument) getAdapter(dtdFile) : null;
}
public class DataTypeImpl implements CMDataType {
public int getNodeType() {
return CMNode.DATA_TYPE;
}
public String getNodeName() {
return getDataTypeName();
}
public boolean supports(String propertyName) {
return false;
}
public Object getProperty(String propertyName) {
Object result = null;
if (propertyName.equals("isValidEmptyValue")) { //$NON-NLS-1$
String dataTypeName = getDataTypeName();
result = (dataTypeName == null || dataTypeName.equals(CMDataType.CDATA)) ? "true" : "false"; //$NON-NLS-1$ //$NON-NLS-2$
}
return result;
}
public String getDataTypeName() {
return cmDataTypeInfoTable.getDataTypeName(attribute.getDTDType());
}
public String generateInstanceValue() {
return cmDataTypeInfoTable.getInstanceValue(attribute.getDTDType());
}
public int getImpliedValueKind() {
int result = IMPLIED_VALUE_NONE;
int defaultValueKind = attribute.getDefaultKind().getValue();
if (defaultValueKind == DTDDefaultKind.NOFIXED) {
result = IMPLIED_VALUE_DEFAULT;
}
else if (defaultValueKind == DTDDefaultKind.FIXED) {
result = IMPLIED_VALUE_FIXED;
}
return result;
}
public String getImpliedValue() {
return attribute.getDefaultValueString();
}
public String[] getEnumeratedValues() {
Object[] objectList = attribute.getEnumeratedValues().toArray();
String[] result = new String[objectList.length];
for (int i = 0; i < objectList.length; i++) {
result[i] = objectList[i].toString();
}
return result;
}
}
}
/**
* DTDElementBaseAdapter
*/
public static abstract class DTDElementBaseAdapter extends DTDBaseAdapter implements CMElementDeclaration {
protected CMDataType dataType;
protected abstract DTDElement getDTDElement();
protected CMDocumentation documentation = null;
public int getNodeType() {
return ELEMENT_DECLARATION;
}
public String getNodeName() {
return getDTDElement().getName();
}
public CMNamedNodeMap getAttributes() {
CMNamedNodeMapImpl result = new CMNamedNodeMapImpl();
List attributeList = getDTDElement().getDTDAttribute();
for (Iterator i = attributeList.iterator(); i.hasNext();) {
DTDAttribute attribute = (DTDAttribute) i.next();
result.getHashtable().put(attribute.getName(), getAdapter(attribute));
}
return result;
}
public CMContent getContent() {
return (CMContent) getAdapter(getDTDElement().getContent());
}
public int getContentType() {
// todo
int result = ELEMENT;
DTDElementContent dtdElementContent = getDTDElement().getContent();
if (dtdElementContent instanceof DTDPCDataContent) {
result = PCDATA;
}
else if (dtdElementContent instanceof DTDGroupContent) {
DTDGroupContent groupContent = (DTDGroupContent) dtdElementContent;
int groupKind = groupContent.getGroupKind().getValue();
if (groupKind == DTDGroupKind.CHOICE) {
List list = groupContent.getContent();
if (list.size() > 0 && list.get(0) instanceof DTDPCDataContent) {
result = MIXED;
}
}
}
else if (dtdElementContent instanceof DTDAnyContent) {
result = ANY;
}
else if (dtdElementContent instanceof DTDEmptyContent) {
result = EMPTY;
}
return result;
}
public String getElementName() {
return getDTDElement().getName();
}
public CMDataType getDataType() {
int contentType = getContentType();
boolean hasDataType = contentType == PCDATA || contentType == MIXED;
return hasDataType ? dataType : null;
}
public CMNamedNodeMap getLocalElements() {
return CMNamedNodeMapImpl.EMPTY_NAMED_NODE_MAP;
}
public CMDocument getCMDocument() {
DTDFile dtdFile = getDTDElement().getDTDFile();
return dtdFile != null ? (CMDocument) getAdapter(dtdFile) : null;
}
protected CMNodeList getDocumentation() {
CMNodeListImpl nodeList = new CMNodeListImpl();
if (documentation == null) {
String comment = getDTDElement().getComment();
if (comment != null) {
String value = ""; //$NON-NLS-1$
StringTokenizer st = new StringTokenizer(comment, "\n"); //$NON-NLS-1$
while (st.hasMoreTokens()) {
value += st.nextToken().trim() + "\n"; //$NON-NLS-1$
}
documentation = new CMDocumentationImpl(value);
}
}
if (documentation != null) {
nodeList.getList().add(documentation);
}
return nodeList;
}
}
public static class CMDocumentationImpl implements CMDocumentation {
protected String value;
public CMDocumentationImpl(String value) {
this.value = value;
}
public String getNodeName() {
return ""; //$NON-NLS-1$
}
public int getNodeType() {
return DOCUMENTATION;
}
public boolean supports(String propertyName) {
return false;
}
public Object getProperty(String propertyName) {
return null;
}
public String getValue() {
return value;
}
public String getLanguage() {
return null;
}
public String getSource() {
return null;
}
}
/**
* DTDElementAdapter
*/
public static class DTDElementAdapter extends DTDElementBaseAdapter {
protected DTDElement element;
public DTDElementAdapter(DTDElement element) {
this.element = element;
dataType = new CMDataTypeImpl("#PCDATA", getDTDElement().getName()); //$NON-NLS-1$
}
public Object getKey() {
return element;
}
protected DTDElement getDTDElement() {
return element;
}
public int getMinOccur() {
return 1;
}
public int getMaxOccur() {
return 1;
}
public String getDefinitionInfo() {
return "global"; //$NON-NLS-1$
}
public CMNode getDefinition() {
return this;
}
}
/**
* DTDElementReferenceContentAdapter
*/
public static class DTDElementReferenceContentAdapter extends DTDElementBaseAdapter {
protected DTDElementReferenceContent content;
public DTDElementReferenceContentAdapter(DTDElementReferenceContent content) {
this.content = content;
dataType = new CMDataTypeImpl("#PCDATA", getDTDElement().getName()); //$NON-NLS-1$
}
public Object getKey() {
return content;
}
protected DTDElement getDTDElement() {
return content.getReferencedElement();
}
public int getMinOccur() {
return getMinOccurHelper(content);
}
public int getMaxOccur() {
return getMaxOccurHelper(content);
}
public CMNode getDefinition() {
return getAdapter(getDTDElement());
}
}
/**
* DTDEntityAdapter
*/
public static class DTDEntityAdapter extends DTDBaseAdapter implements CMEntityDeclaration {
protected DTDEntity dtdEntity;
public DTDEntityAdapter(DTDEntity dtdEntity) {
this.dtdEntity = dtdEntity;
}
public int getNodeType() {
return ENTITY_DECLARATION;
}
public Object getKey() {
return dtdEntity;
}
public String getName() {
return dtdEntity.getName();
}
public String getValue() {
String value = ""; //$NON-NLS-1$
if (dtdEntity.getContent() instanceof DTDInternalEntity) {
DTDInternalEntity content = (DTDInternalEntity) dtdEntity.getContent();
value = content.getValue();
}
return value;
}
}
/**
* DTDGroupContentAdapter
*/
public static class DTDGroupContentAdapter extends DTDBaseAdapter implements CMGroup {
protected DTDGroupContent content;
public DTDGroupContentAdapter(DTDGroupContent content) {
this.content = content;
}
public Object getKey() {
return content;
}
public int getNodeType() {
return GROUP;
}
public String getNodeName() {
CMDescriptionBuilder descriptionBuilder = new CMDescriptionBuilder();
return descriptionBuilder.buildDescription(this);
}
public CMNodeList getChildNodes() {
List list = content.getContent();
CMNodeListImpl result = new CMNodeListImpl();
for (Iterator i = list.iterator(); i.hasNext();) {
CMNode node = getAdapter((Notifier) i.next());
if (node != null) {
result.getList().add(node);
}
}
return result;
}
public int getMaxOccur() {
return getMaxOccurHelper(content);
}
public int getMinOccur() {
return getMinOccurHelper(content);
}
public int getOperator() {
// todo... handle ALONE case by checkig if child count == 1
int groupKind = content.getGroupKind().getValue();
return (groupKind == DTDGroupKind.CHOICE) ? CHOICE : SEQUENCE;
}
}
/**
* DTDFileAdapter
*/
public static class DTDFileAdapter extends DTDBaseAdapter implements CMDocument {
protected final String DEFAULT_ROOT_NAME = "http://org.eclipse.wst/cm/properties/defaultRootName"; //$NON-NLS-1$
protected DTDFile dtdFile;
protected CMNamedNodeMapImpl namedNodeMap;
protected CMNamedNodeMapImpl entityNodeMap;
protected AnnotationMap annotationMap = new AnnotationMap();
protected Map globalPropertyMap = new HashMap();
public DTDFileAdapter(DTDFile dtdFile) {
this.dtdFile = dtdFile;
}
public Object getKey() {
return dtdFile;
}
public AnnotationMap getAnnotationMap() {
return annotationMap;
}
public CMNamedNodeMap getElements() {
if (namedNodeMap == null) {
namedNodeMap = new CMNamedNodeMapImpl();
for (Iterator iterator = dtdFile.listDTDElement().iterator(); iterator.hasNext();) {
DTDElement dtdElement = (DTDElement) iterator.next();
namedNodeMap.getHashtable().put(dtdElement.getName(), getAdapter(dtdElement));
}
}
return namedNodeMap;
}
public CMNamedNodeMap getEntities() {
if (entityNodeMap == null) {
entityNodeMap = new CMNamedNodeMapImpl();
// add the built in entity declarations
//
entityNodeMap.getHashtable().put("amp", new CMEntityDeclarationImpl("amp", "&")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
entityNodeMap.getHashtable().put("lt", new CMEntityDeclarationImpl("lt", "<")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
entityNodeMap.getHashtable().put("gt", new CMEntityDeclarationImpl("gt", ">")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
entityNodeMap.getHashtable().put("quot", new CMEntityDeclarationImpl("quot", "\"")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
entityNodeMap.getHashtable().put("apos", new CMEntityDeclarationImpl("apos", "'")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
for (Iterator i = dtdFile.listDTDEntity().iterator(); i.hasNext();) {
DTDEntity dtdEntity = (DTDEntity) i.next();
if (!dtdEntity.isParameterEntity() && dtdEntity.getName() != null) {
// for now... just handle DTDInternalEntity
//
if (dtdEntity.getContent() instanceof DTDInternalEntity) {
entityNodeMap.getHashtable().put(dtdEntity.getName(), getAdapter(dtdEntity));
}
}
}
}
return entityNodeMap;
}
public CMNamespace getNamespace() {
return null;
}
public int getNodeType() {
return DOCUMENT;
}
public String getNodeName() {
return dtdFile.getName() + ".dtd"; //$NON-NLS-1$
}
public Object getProperty(String propertyName) {
Object result = null;
if (propertyName.equals(DEFAULT_ROOT_NAME)) {
DTDMetrics metrics = new DTDMetrics(dtdFile);
DTDElement dtdElement = metrics.getLeastReferencedElement();
if (dtdElement != null) {
result = dtdElement.getName();
}
}
else if (propertyName.equals("annotationMap")) { //$NON-NLS-1$
result = annotationMap;
}
else if (propertyName.equals("globalPropertyMap")) { //$NON-NLS-1$
result = globalPropertyMap;
}
else {
result = super.getProperty(propertyName);
}
return result;
}
}
public static class CMDataTypeInfoTable {
protected String[] instanceValueTable;
protected String[] dataTypeNameTable;
public CMDataTypeInfoTable() {
// hashtable.put(DTDType.CDATA, null));
instanceValueTable = new String[DTDBasicTypeImpl.basicTypeKinds.length];
instanceValueTable[DTDBasicTypeKind.ENTITY] = "entity"; //$NON-NLS-1$
instanceValueTable[DTDBasicTypeKind.ENTITIES] = "entities"; //$NON-NLS-1$
instanceValueTable[DTDBasicTypeKind.NMTOKEN] = "nmtoken"; //$NON-NLS-1$
instanceValueTable[DTDBasicTypeKind.NMTOKENS] = "nmtokens"; //$NON-NLS-1$
dataTypeNameTable = new String[DTDBasicTypeImpl.basicTypeKinds.length];
dataTypeNameTable[DTDBasicTypeKind.CDATA] = CMDataType.CDATA;
dataTypeNameTable[DTDBasicTypeKind.ID] = CMDataType.ID;
dataTypeNameTable[DTDBasicTypeKind.IDREF] = CMDataType.IDREF;
dataTypeNameTable[DTDBasicTypeKind.ENTITY] = CMDataType.ENTITY;
dataTypeNameTable[DTDBasicTypeKind.ENTITIES] = CMDataType.ENTITIES;
dataTypeNameTable[DTDBasicTypeKind.NMTOKEN] = CMDataType.NMTOKEN;
dataTypeNameTable[DTDBasicTypeKind.NMTOKENS] = CMDataType.NMTOKENS;
}
public String getInstanceValue(DTDType dtdType) {
String result = null;
if (dtdType instanceof DTDBasicType) {
int kind = ((DTDBasicType) dtdType).getKind().getValue();
if (kind >= 0 && kind < DTDBasicTypeImpl.basicTypeDescriptions.length) {
result = instanceValueTable[kind];
}
}
return result;
}
public String getDataTypeName(DTDType dtdType) {
String result = null;
if (dtdType instanceof DTDBasicType) {
int kind = ((DTDBasicType) dtdType).getKind().getValue();
if (kind >= 0 && kind < DTDBasicTypeImpl.basicTypeDescriptions.length) {
result = dataTypeNameTable[kind];
}
}
else if (dtdType instanceof DTDEnumerationType) {
result = CMDataType.ENUM;
}
return result;
}
}
}