| /******************************************************************************* |
| * Copyright (c) 2007 Oracle Corporation. |
| * 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: |
| * Oracle - initial API and implementation |
| * |
| ********************************************************************************/ |
| package org.eclipse.jst.jsf.common.metadata.internal; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.StringTokenizer; |
| |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; |
| import org.eclipse.emf.ecore.util.BasicExtendedMetaData; |
| import org.eclipse.emf.ecore.util.ExtendedMetaData; |
| import org.eclipse.emf.ecore.xmi.ClassNotFoundException; |
| import org.eclipse.emf.ecore.xmi.FeatureNotFoundException; |
| import org.eclipse.emf.ecore.xmi.IllegalValueException; |
| import org.eclipse.emf.ecore.xmi.PackageNotFoundException; |
| import org.eclipse.emf.ecore.xmi.UnresolvedReferenceException; |
| import org.eclipse.emf.ecore.xmi.XMIException; |
| import org.eclipse.emf.ecore.xmi.XMLResource; |
| import org.eclipse.emf.ecore.xmi.impl.XMLResourceFactoryImpl; |
| import org.eclipse.jst.jsf.common.JSFCommonPlugin; |
| import org.eclipse.jst.jsf.common.metadata.Model; |
| import org.eclipse.jst.jsf.common.metadata.internal.util.MetadataResourceImpl; |
| |
| /** |
| * Singleton that produces and loads standard metadata models. |
| * All models are loaded into the same ResourceSet. |
| * <p> |
| * All metadata extension models must be registered with org.eclipse.emf.ecore.generated_package extension-point. |
| * No other mechanism is provided for model uri resolution. |
| * <p> |
| * Debug tracing for model loading is available: <code>org.eclipse.jst.jsf.common/debug/metadataload=true</code> |
| * <p> |
| * When the /debug/metadataload trace flag is set, and in case extension models are known not to be available, |
| * and metadata is referencing those models, error logging can be suppressed by launching with the following properties set:<br> |
| * metadata.package.ignores<br> |
| * metadata.classname.ignores |
| * <p> |
| * eg. Usage for when WPE is not present<p> |
| * <code> |
| -Dmetadata.package.ignores=http://org.eclipse.jsf.pagedesigner/dtinfo.ecore,<br>http://org.eclipse.jsf.pagedesigner/QuickEditTabSections.ecore<br> |
| -Dmetadata.classname.ignores=DTInfo,QuickEditTabSections<br> |
| * </code> |
| * <p> |
| * see {@link Model} |
| */ |
| public class StandardModelFactory { |
| private static StandardModelFactory INSTANCE; |
| static boolean DEBUG_MD_LOAD = false; |
| static boolean DEBUG_MD_GET = false; |
| private ExtendedMetaData extendedMetaData; |
| private ResourceSet resourceSet; |
| |
| |
| /** |
| * @return singleton instance of the metadata model factory |
| */ |
| public synchronized static StandardModelFactory getInstance(){ |
| if (INSTANCE == null){ |
| INSTANCE = new StandardModelFactory(); |
| INSTANCE.init(); |
| |
| if (JSFCommonPlugin.getPlugin().isDebugging()){ |
| DEBUG_MD_LOAD = Boolean.valueOf(Platform.getDebugOption(JSFCommonPlugin.PLUGIN_ID+"/debug/metadataload")).booleanValue();//$NON-NLS-1$ |
| DEBUG_MD_GET = Boolean.valueOf(Platform.getDebugOption(JSFCommonPlugin.PLUGIN_ID+"/debug/metadataget")).booleanValue();//$NON-NLS-1$ |
| } |
| } |
| return INSTANCE; |
| } |
| |
| private void init() { |
| resourceSet = new ResourceSetImpl(); |
| |
| extendedMetaData = new BasicExtendedMetaData(resourceSet.getPackageRegistry()); |
| |
| // Register the appropriate resource factory to handle all file extensions. |
| // |
| resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put |
| (Resource.Factory.Registry.DEFAULT_EXTENSION, |
| new XMLResourceFactoryImpl()); |
| |
| //relying on the org.eclipse.emf.ecore.generated_package ext-pt to register traits |
| } |
| |
| private StandardModelFactory() { |
| super(); |
| } |
| |
| // /** |
| // * Factory method that probably belongs somewhere else! |
| // * @param key |
| // * @param strategy |
| // * @return an empty MetaDataModel |
| // * @deprecated |
| // */ |
| // public MetaDataModel createModel(ModelKeyDescriptor key, IDomainLoadingStrategy strategy){ |
| // return new MetaDataModel(key, strategy); |
| // } |
| |
| /** |
| * @param context |
| * @param strategy |
| * @return MetaDataModel |
| */ |
| public MetaDataModel createModel(final IMetaDataModelContext context, final IDomainLoadingStrategy strategy) { |
| return new MetaDataModel(context, strategy); |
| } |
| // |
| // /** |
| // * Factory method that probably belongs somewhere else! |
| // * @param modelContext |
| // * @return a ModelKeyDescriptor for the context |
| // * @deprecated |
| // */ |
| // public ModelKeyDescriptor createModelKeyDescriptor(final ITaglibDomainMetaDataModelContext modelContext) { |
| // return new ModelKeyDescriptor(modelContext.getProject(), modelContext.getDomainID(), modelContext.getURI()); |
| // } |
| |
| /** |
| * @param inputStream |
| * @param provider |
| * @param uri |
| * @return the root of the standard model from the resource as an EList |
| * @throws IOException |
| */ |
| public EList loadStandardFileResource(final InputStream inputStream, |
| final IMetaDataSourceModelProvider provider, |
| final org.eclipse.emf.common.util.URI uri) throws IOException |
| { |
| final XMLResource res = new MetadataResourceImpl(provider); |
| |
| debug(String.format( |
| ">>> Loading standard meta-data file for uri %s", uri), DEBUG_MD_LOAD); //$NON-NLS-1$ |
| |
| res.setURI(uri); |
| resourceSet.getResources().add(res); |
| setLoadOptions(res); |
| res.load(inputStream, null); |
| if (DEBUG_MD_LOAD) |
| { |
| reportErrors(res); |
| } |
| final EList root = res.getContents(); |
| return root; |
| } |
| |
| private void reportErrors(Resource res) { |
| EList<Resource.Diagnostic> errs = res.getErrors(); |
| if (! errs.isEmpty()){ |
| for (Iterator<Resource.Diagnostic> it= errs.iterator();it.hasNext();){ |
| StandardModelErrorMessageFactory.logErrorMessage(it.next()); |
| } |
| } |
| } |
| |
| /** |
| * Sets default load options for the resource |
| * @param resource |
| */ |
| protected void setLoadOptions(XMLResource resource) { |
| Map options = resource.getDefaultLoadOptions(); |
| // options.put(XMLResource.OPTION_SAVE_TYPE_INFORMATION, true); |
| options.put(XMLResource.OPTION_SCHEMA_LOCATION, Boolean.TRUE); |
| options.put(XMLResource.OPTION_EXTENDED_META_DATA, extendedMetaData); |
| options.put(XMLResource.OPTION_RESOURCE_HANDLER, resource); |
| options.put(XMLResource.OPTION_LAX_FEATURE_PROCESSING, Boolean.TRUE); |
| options.put(XMLResource.OPTION_RECORD_UNKNOWN_FEATURE, Boolean.FALSE);//turning this off so that res.getErrors() has values to check! bizarre that I should need to do this. |
| // options.put(XMLResource.OPTION_DOM_USE_NAMESPACES_IN_SCOPE, Boolean.TRUE); |
| |
| // if (DEBUG_MD_LOAD) |
| // { |
| // System.out.println("Using load options: "+options); |
| // } |
| } |
| |
| |
| static class StandardModelErrorMessageFactory { |
| private static List<String> _missingPackageURIs; |
| private static List<String> _missingClassnames; |
| |
| /** |
| * Simply logs all messages against JSFCommonPlugin, for now. |
| * @param diagnostic |
| */ |
| public static void logErrorMessage(Resource.Diagnostic diagnostic) { |
| //should be XMIException |
| if (diagnostic instanceof XMIException) { |
| XMIException ex = (XMIException)diagnostic; |
| String msg = createMessage(ex); |
| if (msg != null) |
| JSFCommonPlugin.log(IStatus.ERROR, msg); |
| } |
| else { |
| JSFCommonPlugin.log(IStatus.ERROR, diagnostic.toString());//do better??? |
| } |
| } |
| |
| private static String createMessage(XMIException ex) { |
| |
| StringBuffer buf = new StringBuffer("Metadata Load Error: ") //$NON-NLS-1$ |
| .append(ex.getClass().getSimpleName()).append(": "); //$NON-NLS-1$ |
| |
| if (ex instanceof PackageNotFoundException) { |
| if (shouldIgnore(ex)) |
| return null; |
| |
| buf.append(((PackageNotFoundException)ex).uri()); |
| } |
| else if (ex instanceof ClassNotFoundException) { |
| if (shouldIgnore(ex)) |
| return null; |
| |
| buf.append(((ClassNotFoundException)ex).getName()); |
| } |
| else if (ex instanceof FeatureNotFoundException) |
| buf.append(((FeatureNotFoundException)ex).getName()); |
| else if (ex instanceof IllegalValueException) |
| buf.append(((IllegalValueException)ex).getValue().toString()); |
| else if (ex instanceof UnresolvedReferenceException) |
| buf.append(((UnresolvedReferenceException)ex).getReference()); |
| else |
| buf.append(ex.getMessage()); |
| |
| buf.append(" in ").append(ex.getLocation()).append(": Line = ") //$NON-NLS-1$ //$NON-NLS-2$ |
| .append(ex.getLine()).append(": Column = ").append(ex.getColumn()); //$NON-NLS-1$ |
| return buf.toString(); |
| } |
| |
| private static boolean shouldIgnore(XMIException ex) { |
| if (ex instanceof PackageNotFoundException) { |
| String uri = ((PackageNotFoundException)ex).uri(); |
| return getMissingPackageURIs().contains(uri); |
| } |
| else if (ex instanceof ClassNotFoundException) { |
| String className = ((ClassNotFoundException)ex).getName(); |
| return getMissingClassnames().contains(className); |
| } |
| return false; |
| } |
| |
| private static List<String> getMissingPackageURIs() { |
| if (_missingPackageURIs == null) { |
| _missingPackageURIs = buildList("metadata.package.ignores"); //$NON-NLS-1$ |
| |
| } |
| return _missingPackageURIs; |
| } |
| |
| private static List<String> getMissingClassnames() { |
| if (_missingClassnames == null) { |
| _missingClassnames = buildList("metadata.classname.ignores"); //$NON-NLS-1$ |
| } |
| return _missingClassnames; |
| } |
| |
| private static List<String> buildList(String propertyName) { |
| List<String> ret = new ArrayList<String>(); |
| String ignoreSet = System.getProperty(propertyName); |
| if (ignoreSet == null )//try env |
| ignoreSet = System.getenv(propertyName); |
| |
| if (ignoreSet != null && !(ignoreSet.equals(""))){ //$NON-NLS-1$ |
| StringTokenizer st = new StringTokenizer(ignoreSet, ","); //$NON-NLS-1$ |
| while(st.hasMoreTokens()){ |
| String uri = st.nextToken(); |
| if (!(uri.equals(""))) //$NON-NLS-1$ |
| ret.add(uri); |
| } |
| } |
| |
| return ret; |
| } |
| |
| } |
| |
| /** |
| * Debug output. The parenthesis shows thread id. |
| * @param msg |
| * @param debugFlag |
| */ |
| public static void debug(String msg, boolean debugFlag) { |
| if (debugFlag) |
| System.out.println(msg + "["+Thread.currentThread().getId()+"]"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| |
| } |