/*******************************************************************************
* Copyright (c) 2004, 2006
* Thomas Hallgren, Kenneth Olwing, Mitch Sonies
* Pontus Rydin, Nils Unden, Peer Torngren
* The code, documentation and other materials contained herein have been
* licensed under the Eclipse Public License - v 1.0 by the individual
* copyright holders listed above, as Initial Contributors under such license.
* The text of such license is available at www.eclipse.org.
*******************************************************************************/
package org.eclipse.buckminster.core.parser;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.buckminster.core.CorePlugin;
import org.eclipse.buckminster.core.Messages;
import org.eclipse.buckminster.core.cspec.model.CSpec;
import org.eclipse.buckminster.core.cspec.parser.CSpecParser;
import org.eclipse.buckminster.core.cspecext.model.CSpecExtension;
import org.eclipse.buckminster.core.cspecext.parser.AlterCSpecParser;
import org.eclipse.buckminster.core.metadata.model.BOMNode;
import org.eclipse.buckminster.core.metadata.model.BillOfMaterials;
import org.eclipse.buckminster.core.metadata.model.Materialization;
import org.eclipse.buckminster.core.metadata.model.Resolution;
import org.eclipse.buckminster.core.metadata.model.WorkspaceBinding;
import org.eclipse.buckminster.core.metadata.parser.BillOfMaterialsParser;
import org.eclipse.buckminster.core.metadata.parser.DepNodeParser;
import org.eclipse.buckminster.core.metadata.parser.MaterializationParser;
import org.eclipse.buckminster.core.metadata.parser.ResolutionParser;
import org.eclipse.buckminster.core.metadata.parser.WorkspaceBindingParser;
import org.eclipse.buckminster.core.mspec.model.MaterializationSpec;
import org.eclipse.buckminster.core.mspec.parser.MaterializationSpecParser;
import org.eclipse.buckminster.core.query.model.ComponentQuery;
import org.eclipse.buckminster.core.query.parser.ComponentQueryParser;
import org.eclipse.buckminster.core.rmap.model.Provider;
import org.eclipse.buckminster.core.rmap.model.ResourceMap;
import org.eclipse.buckminster.core.rmap.parser.ProviderParser;
import org.eclipse.buckminster.core.rmap.parser.ResourceMapParser;
import org.eclipse.buckminster.runtime.BuckminsterException;
import org.eclipse.buckminster.sax.AbstractHandler;
import org.eclipse.buckminster.sax.ChildHandler;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.Platform;
import org.osgi.framework.Bundle;
public class ParserFactory implements IParserFactory {
public static class ParserExtension {
private final String namespace;
private final URL resource;
private final Map<String, Class<? extends ChildHandler>> handlers = new HashMap<String, Class<? extends ChildHandler>>();
public ParserExtension(String namespace, URL resource) {
this.namespace = namespace;
this.resource = resource;
}
public final ChildHandler getHandler(AbstractHandler parent, String xsiType) throws CoreException {
Class<? extends ChildHandler> handlerClass = handlers.get(xsiType);
try {
Constructor<? extends ChildHandler> ctor = handlerClass.getConstructor(new Class[] { AbstractHandler.class });
return ctor.newInstance(new Object[] { parent });
} catch (Exception e) {
throw BuckminsterException.wrap(e);
}
}
public final String getNamespace() {
return namespace;
}
public final URL getResource() {
return resource;
}
void addHandler(String xsiType, Class<? extends ChildHandler> clazz) {
handlers.put(xsiType, clazz);
}
}
public static final String PARSER_EXTENSIONS_POINT = CorePlugin.CORE_NAMESPACE + ".parserExtensions"; //$NON-NLS-1$
private static final ParserFactory instance = new ParserFactory();
public static IParserFactory getDefault() {
return instance;
}
private Map<String, List<ParserExtension>> parserExtensions;
@Override
public IParser<CSpecExtension> getAlterCSpecParser(boolean validating) throws CoreException {
return new AlterCSpecParser(getParserExtensions(CSpec.TAG, CSpecExtension.TAG), validating);
}
@Override
public IParser<BillOfMaterials> getBillOfMaterialsParser(boolean validating) throws CoreException {
return new BillOfMaterialsParser(getParserExtensions(BillOfMaterials.TAG, ComponentQuery.TAG, Provider.TAG, CSpec.TAG, Resolution.TAG,
BOMNode.TAG), validating);
}
@Override
public IParser<ComponentQuery> getComponentQueryParser(boolean validating) throws CoreException {
return new ComponentQueryParser(getParserExtensions(ComponentQuery.TAG), validating);
}
@Override
public IParser<CSpec> getCSpecParser(boolean validating) throws CoreException {
return new CSpecParser(getParserExtensions(CSpec.TAG), validating);
}
@Override
public IParser<BOMNode> getDepNodeParser() throws CoreException {
return new DepNodeParser(getParserExtensions(Resolution.TAG, BOMNode.TAG));
}
@Override
public IParser<Materialization> getMaterializationParser() throws CoreException {
return new MaterializationParser(getParserExtensions(Materialization.TAG));
}
@Override
public IParser<MaterializationSpec> getMaterializationSpecParser(boolean validating) throws CoreException {
return new MaterializationSpecParser(getParserExtensions(MaterializationSpec.TAG), validating);
}
@Override
public IParser<Provider> getProviderParser(boolean validating) throws CoreException {
return new ProviderParser(getParserExtensions(Provider.TAG), validating);
}
@Override
public IParser<Resolution> getResolutionParser() throws CoreException {
return new ResolutionParser(getParserExtensions(Resolution.TAG));
}
@Override
public IParser<ResourceMap> getResourceMapParser(boolean validating) throws CoreException {
return new ResourceMapParser(getParserExtensions(ResourceMap.TAG, Provider.TAG), validating);
}
@Override
public IParser<WorkspaceBinding> getWorkspaceBindingParser(boolean validating) throws CoreException {
return new WorkspaceBindingParser(getParserExtensions(Provider.TAG, CSpec.TAG, Resolution.TAG), validating);
}
private synchronized List<ParserExtension> getParserExtensions(String... parserIds) {
if (parserExtensions == null) {
try {
parserExtensions = loadParserExtensions();
} catch (CoreException e) {
CorePlugin.getLogger().warning(e, Messages.Unable_to_load_parser_extensions);
parserExtensions = Collections.emptyMap();
}
}
List<ParserExtension> result = null;
boolean mutable = false;
for (String parserId : parserIds) {
List<ParserExtension> pel = parserExtensions.get(parserId);
if (pel == null)
continue;
if (result == null) {
result = pel;
continue;
}
if (!mutable) {
ArrayList<ParserExtension> mutableList = new ArrayList<ParserExtension>();
mutableList.addAll(result);
result = mutableList;
mutable = true;
}
result.addAll(pel);
}
return (result == null || result.size() == 0) ? Collections.<ParserExtension> emptyList() : result;
}
private Map<String, List<ParserExtension>> loadParserExtensions() throws CoreException {
IExtensionRegistry exReg = Platform.getExtensionRegistry();
HashMap<String, List<ParserExtension>> peMap = new HashMap<String, List<ParserExtension>>();
for (IConfigurationElement namespace : exReg.getConfigurationElementsFor(PARSER_EXTENSIONS_POINT)) {
Bundle bundle = Platform.getBundle(namespace.getNamespaceIdentifier());
URL resource = bundle.getResource(namespace.getAttribute("resource")); //$NON-NLS-1$
ParserExtension pe = new ParserExtension(namespace.getAttribute("namespace"), resource); //$NON-NLS-1$
for (IConfigurationElement handler : namespace.getChildren("handler")) //$NON-NLS-1$
{
try {
pe.addHandler(handler.getAttribute("type"), ((Class<?>) bundle.loadClass(handler //$NON-NLS-1$
.getAttribute("class"))).asSubclass(ChildHandler.class)); //$NON-NLS-1$
} catch (ClassNotFoundException e) {
throw BuckminsterException.wrap(e);
}
}
for (String parserId : namespace.getAttribute("parserIds").split(",")) //$NON-NLS-1$ //$NON-NLS-2$
{
List<ParserExtension> peList = peMap.get(parserId);
if (peList == null) {
peList = new ArrayList<ParserExtension>();
peMap.put(parserId, peList);
}
peList.add(pe);
}
}
return peMap;
}
}