blob: d84c99d8487874c968e78b01636b79eda92d7f81 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2011 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.equinox.metatype;
import java.io.IOException;
import java.util.*;
import javax.xml.parsers.SAXParserFactory;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
import org.osgi.service.log.LogService;
import org.osgi.service.metatype.*;
/**
* Implementation of MetaTypeProvider
*/
public class MetaTypeProviderImpl implements MetaTypeProvider {
public static final String METADATA_NOT_FOUND = "METADATA_NOT_FOUND"; //$NON-NLS-1$
public static final String OCD_ID_NOT_FOUND = "OCD_ID_NOT_FOUND"; //$NON-NLS-1$
public static final String ASK_INVALID_LOCALE = "ASK_INVALID_LOCALE"; //$NON-NLS-1$
public static final String META_FILE_EXT = ".XML"; //$NON-NLS-1$
public static final String RESOURCE_FILE_CONN = "_"; //$NON-NLS-1$
public static final String RESOURCE_FILE_EXT = ".properties"; //$NON-NLS-1$
public static final char DIRECTORY_SEP = '/';
Bundle _bundle;
Hashtable<String, ObjectClassDefinitionImpl> _allPidOCDs = new Hashtable<String, ObjectClassDefinitionImpl>(7);
Hashtable<String, ObjectClassDefinitionImpl> _allFPidOCDs = new Hashtable<String, ObjectClassDefinitionImpl>(7);
String[] _locales;
boolean _isThereMeta = false;
// Give access to subclasses.
protected final LogService logger;
/**
* Constructor of class MetaTypeProviderImpl.
*/
MetaTypeProviderImpl(Bundle bundle, SAXParserFactory parserFactory, LogService logger) throws IOException {
this._bundle = bundle;
this.logger = logger;
// read all bundle's metadata files and build internal data structures
_isThereMeta = readMetaFiles(bundle, parserFactory);
if (!_isThereMeta) {
logger.log(LogService.LOG_DEBUG, NLS.bind(MetaTypeMsg.METADATA_NOT_FOUND, new Long(bundle.getBundleId()), bundle.getSymbolicName()));
}
}
/**
* This method should do the following:
* <p> - Obtain a SAX parser from the XML Parser Service:
* <p>
*
* <pre> </pre>
*
* The parser may be SAX 1 (eXML) or SAX 2 (XML4J). It should attempt to use
* a SAX2 parser by instantiating an XMLReader and extending DefaultHandler
* BUT if that fails it should fall back to instantiating a SAX1 Parser and
* extending HandlerBase.
* <p> - Pass the parser the URL for the bundle's METADATA.XML file
* <p> - Handle the callbacks from the parser and build the appropriate
* MetaType objects - ObjectClassDefinitions & AttributeDefinitions
*
* @param bundle The bundle object for which the metadata should be read
* @param parserFactory The bundle object for which the metadata should be
* read
* @return void
* @throws IOException If there are errors accessing the metadata.xml file
*/
private boolean readMetaFiles(Bundle bundle, SAXParserFactory parserFactory) throws IOException {
boolean isThereMetaHere = false;
Enumeration<String> allFileKeys = FragmentUtils.findEntryPaths(bundle, MetaTypeService.METATYPE_DOCUMENTS_LOCATION);
if (allFileKeys == null)
return isThereMetaHere;
while (allFileKeys.hasMoreElements()) {
boolean _isMetaDataFile;
String fileName = allFileKeys.nextElement();
Collection<Designate> designates = null;
java.net.URL[] urls = FragmentUtils.findEntries(bundle, fileName);
if (urls != null) {
for (int i = 0; i < urls.length; i++) {
try {
// Assume all XML files are what we want by default.
_isMetaDataFile = true;
DataParser parser = new DataParser(bundle, urls[i], parserFactory, logger);
designates = parser.doParse();
if (designates.isEmpty()) {
_isMetaDataFile = false;
}
} catch (Exception e) {
// Ok, looks like it is not what we want.
_isMetaDataFile = false;
}
if (_isMetaDataFile) {
// We got some OCDs now.
isThereMetaHere = true;
for (Designate d : designates) {
if (d.isFactory()) {
_allFPidOCDs.put(d.getFactoryPid(), d.getObjectClassDefinition());
} else {
_allPidOCDs.put(d.getPid(), d.getObjectClassDefinition());
}
}
}
}
} // End of if(urls!=null)
} // End of while
return isThereMetaHere;
}
/*
* (non-Javadoc)
*
* @see org.osgi.service.metatype.MetaTypeProvider#getObjectClassDefinition(java.lang.String,
* java.lang.String)
*/
public ObjectClassDefinition getObjectClassDefinition(String pid, String locale) {
if (isInvalidLocale(locale)) {
throw new IllegalArgumentException(NLS.bind(MetaTypeMsg.ASK_INVALID_LOCALE, pid, locale));
}
ObjectClassDefinitionImpl ocd;
if (_allPidOCDs.containsKey(pid)) {
ocd = (ObjectClassDefinitionImpl) (_allPidOCDs.get(pid)).clone();
ocd.setResourceBundle(locale, _bundle);
return ocd;
} else if (_allFPidOCDs.containsKey(pid)) {
ocd = (ObjectClassDefinitionImpl) (_allFPidOCDs.get(pid)).clone();
ocd.setResourceBundle(locale, _bundle);
return ocd;
} else {
throw new IllegalArgumentException(NLS.bind(MetaTypeMsg.OCD_ID_NOT_FOUND, pid));
}
}
/**
* Internal Method - Check if the locale is invalid.
*/
public boolean isInvalidLocale(String locale) {
// Just a simple and quick check here.
if (locale == null || locale.length() == 0)
return false;
int idx_first = locale.indexOf(ObjectClassDefinitionImpl.LOCALE_SEP);
int idx_second = locale.lastIndexOf(ObjectClassDefinitionImpl.LOCALE_SEP);
if (idx_first == -1 && locale.length() == 2)
// It is format of only language.
return false;
if ((idx_first == 2) && (idx_second == 5 || idx_second == 2))
// It is format of language + "_" + country [ + "_" + variation ].
return false;
return true;
}
/*
* (non-Javadoc)
*
* @see org.osgi.service.metatype.MetaTypeProvider#getLocales()
*/
public synchronized String[] getLocales() {
if (_locales != null)
return checkForDefault(_locales);
Vector<String> localizationFiles = new Vector<String>(7);
// get all the localization resources for PIDS
Enumeration<ObjectClassDefinitionImpl> ocds = _allPidOCDs.elements();
while (ocds.hasMoreElements()) {
ObjectClassDefinitionImpl ocd = ocds.nextElement();
if (ocd._localization != null && !localizationFiles.contains(ocd._localization))
localizationFiles.add(ocd._localization);
}
// get all the localization resources for FPIDS
ocds = _allFPidOCDs.elements();
while (ocds.hasMoreElements()) {
ObjectClassDefinitionImpl ocd = ocds.nextElement();
if (ocd._localization != null && !localizationFiles.contains(ocd._localization))
localizationFiles.add(ocd._localization);
}
if (localizationFiles.size() == 0)
localizationFiles.add(Constants.BUNDLE_LOCALIZATION_DEFAULT_BASENAME);
Vector<String> locales = new Vector<String>(7);
Enumeration<String> eLocalizationFiles = localizationFiles.elements();
while (eLocalizationFiles.hasMoreElements()) {
String localizationFile = eLocalizationFiles.nextElement();
int iSlash = localizationFile.lastIndexOf(DIRECTORY_SEP);
String baseDir;
String baseFileName;
if (iSlash < 0) {
baseDir = ""; //$NON-NLS-1$
} else {
baseDir = localizationFile.substring(0, iSlash);
}
baseFileName = localizationFile + RESOURCE_FILE_CONN;
Enumeration<String> resources = FragmentUtils.findEntryPaths(this._bundle, baseDir);
if (resources != null) {
while (resources.hasMoreElements()) {
String resource = resources.nextElement();
if (resource.startsWith(baseFileName) && resource.toLowerCase().endsWith(RESOURCE_FILE_EXT))
locales.add(resource.substring(baseFileName.length(), resource.length() - RESOURCE_FILE_EXT.length()));
}
}
}
_locales = locales.toArray(new String[locales.size()]);
return checkForDefault(_locales);
}
/**
* Internal Method - checkForDefault
*/
private String[] checkForDefault(String[] locales) {
if (locales == null || locales.length == 0 || (locales.length == 1 && Locale.getDefault().toString().equals(locales[0])))
return null;
return locales;
}
}