View | Details | Raw Unified | Return to bug 349711 | Differences between
and this patch

Collapse All | Expand All

(-).classpath (+1 lines)
Lines 10-14 Link Here
10
	<classpathentry kind="src" output="bundle_tests/metatype/tb5" path="bundles_src/metatype/tb5"/>
10
	<classpathentry kind="src" output="bundle_tests/metatype/tb5" path="bundles_src/metatype/tb5"/>
11
	<classpathentry kind="src" output="bundle_tests/metatype/tb6" path="bundles_src/metatype/tb6"/>
11
	<classpathentry kind="src" output="bundle_tests/metatype/tb6" path="bundles_src/metatype/tb6"/>
12
	<classpathentry kind="src" output="bundle_tests/metatype/tb7" path="bundles_src/metatype/tb7"/>
12
	<classpathentry kind="src" output="bundle_tests/metatype/tb7" path="bundles_src/metatype/tb7"/>
13
	<classpathentry kind="src" output="bundle_tests/metatype/extendable.tb1" path="bundles_src/metatype/extendable.tb1"/>
13
	<classpathentry kind="output" path="bin"/>
14
	<classpathentry kind="output" path="bin"/>
14
</classpath>
15
</classpath>
(-)build.properties (-1 / +4 lines)
Lines 29-34 Link Here
29
manifest.bundle_tests/metatype.tb6.jar = META-INF/MANIFEST.MF
29
manifest.bundle_tests/metatype.tb6.jar = META-INF/MANIFEST.MF
30
source.bundle_tests/metatype.tb7.jar = bundles_src/metatype/tb7/
30
source.bundle_tests/metatype.tb7.jar = bundles_src/metatype/tb7/
31
manifest.bundle_tests/metatype.tb7.jar = META-INF/MANIFEST.MF
31
manifest.bundle_tests/metatype.tb7.jar = META-INF/MANIFEST.MF
32
source.bundle_tests/metatype.extendable.tb1.jar = bundles_src/metatype/extendable.tb1/
33
manifest.bundle_tests/metatype.extendable.tb1.jar = META-INF/MANIFEST.MF
32
34
33
jars.compile.order = bundle_tests/metatype/metatype.tb1.jar,\
35
jars.compile.order = bundle_tests/metatype/metatype.tb1.jar,\
34
                     bundle_tests/metatype/metatype.tb2.jar,\
36
                     bundle_tests/metatype/metatype.tb2.jar,\
Lines 36-39 Link Here
36
                     bundle_tests/metatype/metatype.tb4.jar,\
38
                     bundle_tests/metatype/metatype.tb4.jar,\
37
                     bundle_tests/metatype/metatype.tb5.jar,\
39
                     bundle_tests/metatype/metatype.tb5.jar,\
38
                     bundle_tests/metatype/metatype.tb6.jar,\
40
                     bundle_tests/metatype/metatype.tb6.jar,\
39
                     bundle_tests/metatype/metatype.tb7.jar
41
                     bundle_tests/metatype/metatype.tb7.jar,\
42
                     bundle_tests/metatype/metatype.extendable.tb1.jar
(-)META-INF/MANIFEST.MF (-1 / +2 lines)
Lines 2-12 Link Here
2
Bundle-ManifestVersion: 2
2
Bundle-ManifestVersion: 2
3
Bundle-Name: %bundleName
3
Bundle-Name: %bundleName
4
Bundle-SymbolicName: org.eclipse.equinox.compendium.tests
4
Bundle-SymbolicName: org.eclipse.equinox.compendium.tests
5
Bundle-Version: 1.1.0
5
Bundle-Version: 1.1.100
6
Bundle-Activator: org.eclipse.equinox.compendium.tests.Activator
6
Bundle-Activator: org.eclipse.equinox.compendium.tests.Activator
7
Require-Bundle: org.eclipse.core.runtime
7
Require-Bundle: org.eclipse.core.runtime
8
Eclipse-LazyStart: true
8
Eclipse-LazyStart: true
9
Import-Package: junit.framework;version="3.8.2",
9
Import-Package: junit.framework;version="3.8.2",
10
 org.eclipse.equinox.metatype;version="1.2.0",
10
 org.eclipse.osgi.tests.bundles,
11
 org.eclipse.osgi.tests.bundles,
11
 org.osgi.framework;version="1.3.0",
12
 org.osgi.framework;version="1.3.0",
12
 org.osgi.service.event;version="1.1.0",
13
 org.osgi.service.event;version="1.1.0",
(-)bundles_src/metatype/extendable.tb1/META-INF/MANIFEST.MF (+8 lines)
Added Link Here
1
Manifest-Version: 1.0
2
Bundle-ManifestVersion: 2
3
Bundle-SymbolicName: metatype.extendable.tb1
4
Bundle-Version: 1.0.0
5
Import-Package: org.osgi.framework;version="1.3.0",
6
 org.osgi.service.metatype;version="1.2"
7
Bundle-RequiredExecutionEnvironment: J2SE-1.4
8
(-)bundles_src/metatype/extendable.tb1/OSGI-INF/metatype/metadata.xml (+14 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<md:MetaData 
3
		xmlns:md="http://www.org.osgi/xmlns/metatype/v1.2.0/md" 
4
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
5
		xsi:schemaLocation="http://www.org.osgi/xmlns/metatype/v1.2.0/md metatype.xsd"
6
		xmlns:validation="urn:xmlns:validation"
7
		xmlns:foo="urn:xmlns:foo">
8
	<OCD id="ocd1" name="ocd1" foo:foo="bar" validation:enabled="true">
9
		<AD name="ad1" id="ad1" type="String" validation:regexp="[a-zA-Z0-9]" validation:validation="validation" foo:bar="foo"/>
10
	</OCD>
11
	<Designate pid="metatype.extendable.tb1.1">
12
		<Object ocdref="ocd1"/>
13
	</Designate>
14
</md:MetaData>
(-)src/org/eclipse/equinox/compendium/tests/AllTests.java (-1 / +3 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2008, 2010 IBM Corporation and others
2
 * Copyright (c) 2008, 2011 IBM Corporation and others
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 18-23 Link Here
18
	public static Test suite() {
18
	public static Test suite() {
19
		TestSuite suite = new TestSuite("Tests for Equinox Compendium"); //$NON-NLS-1$
19
		TestSuite suite = new TestSuite("Tests for Equinox Compendium"); //$NON-NLS-1$
20
		suite.addTest(org.eclipse.equinox.metatype.tests.AllTests.suite());
20
		suite.addTest(org.eclipse.equinox.metatype.tests.AllTests.suite());
21
		// Second run for EquinoxMetaTypeService.
22
		suite.addTest(org.eclipse.equinox.metatype.tests.AllTests.suite());
21
		suite.addTest(org.eclipse.equinox.useradmin.tests.AllTests.suite());
23
		suite.addTest(org.eclipse.equinox.useradmin.tests.AllTests.suite());
22
		suite.addTest(org.eclipse.equinox.event.tests.AllTests.suite());
24
		suite.addTest(org.eclipse.equinox.event.tests.AllTests.suite());
23
		return suite;
25
		return suite;
(-)src/org/eclipse/equinox/metatype/tests/AbstractTest.java (-6 / +6 lines)
Lines 10-27 Link Here
10
 *******************************************************************************/
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype.tests;
11
package org.eclipse.equinox.metatype.tests;
12
12
13
import org.eclipse.equinox.metatype.EquinoxMetaTypeService;
14
13
import junit.framework.TestCase;
15
import junit.framework.TestCase;
14
import org.eclipse.equinox.compendium.tests.Activator;
16
import org.eclipse.equinox.compendium.tests.Activator;
15
import org.eclipse.osgi.tests.bundles.BundleInstaller;
17
import org.eclipse.osgi.tests.bundles.BundleInstaller;
16
import org.osgi.framework.ServiceReference;
18
import org.osgi.framework.ServiceReference;
17
import org.osgi.service.metatype.AttributeDefinition;
19
import org.osgi.service.metatype.AttributeDefinition;
18
import org.osgi.service.metatype.MetaTypeService;
19
20
20
public abstract class AbstractTest extends TestCase {
21
public abstract class AbstractTest extends TestCase {
21
	protected BundleInstaller bundleInstaller;
22
	protected BundleInstaller bundleInstaller;
22
	protected MetaTypeService metatype;
23
	protected EquinoxMetaTypeService metatype;
23
24
	protected ServiceReference metaTypeReference;
24
	private ServiceReference metaTypeReference;
25
25
26
	protected void assertValidationFail(String value, AttributeDefinition ad) {
26
	protected void assertValidationFail(String value, AttributeDefinition ad) {
27
		String result = assertValidationPresent(value, ad);
27
		String result = assertValidationPresent(value, ad);
Lines 75-83 Link Here
75
75
76
	protected void setUp() throws Exception {
76
	protected void setUp() throws Exception {
77
		Activator.getBundle(Activator.BUNDLE_METATYPE).start();
77
		Activator.getBundle(Activator.BUNDLE_METATYPE).start();
78
		metaTypeReference = Activator.getBundleContext().getServiceReference(MetaTypeService.class.getName());
78
		metaTypeReference = Activator.getBundleContext().getServiceReference(EquinoxMetaTypeService.class.getName());
79
		assertNotNull("Metatype service reference not found", metaTypeReference); //$NON-NLS-1$
79
		assertNotNull("Metatype service reference not found", metaTypeReference); //$NON-NLS-1$
80
		metatype = (MetaTypeService) Activator.getBundleContext().getService(metaTypeReference);
80
		metatype = (EquinoxMetaTypeService) Activator.getBundleContext().getService(metaTypeReference);
81
		assertNotNull("Metatype service not found", metatype); //$NON-NLS-1$
81
		assertNotNull("Metatype service not found", metatype); //$NON-NLS-1$
82
		bundleInstaller = new BundleInstaller("bundle_tests/metatype", Activator.getBundleContext()); //$NON-NLS-1$
82
		bundleInstaller = new BundleInstaller("bundle_tests/metatype", Activator.getBundleContext()); //$NON-NLS-1$
83
	}
83
	}
(-)src/org/eclipse/equinox/metatype/tests/AllTests.java (+1 lines)
Lines 21-26 Link Here
21
		suite.addTestSuite(Bug340899Test.class);
21
		suite.addTestSuite(Bug340899Test.class);
22
		suite.addTestSuite(BugTests.class);
22
		suite.addTestSuite(BugTests.class);
23
		suite.addTestSuite(SameOcdPidFactoryPidTest.class);
23
		suite.addTestSuite(SameOcdPidFactoryPidTest.class);
24
		suite.addTestSuite(ExtendableTest.class);
24
		return suite;
25
		return suite;
25
	}
26
	}
26
}
27
}
(-)src/org/eclipse/equinox/metatype/tests/ExtendableTest.java (+65 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 IBM Corporation and others
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype.tests;
12
13
import org.eclipse.equinox.metatype.*;
14
15
import java.util.Map;
16
import java.util.Set;
17
import org.osgi.framework.Bundle;
18
import org.osgi.service.metatype.ObjectClassDefinition;
19
20
public class ExtendableTest extends AbstractTest {
21
	private Bundle bundle;
22
23
	protected void setUp() throws Exception {
24
		super.setUp();
25
		bundle = bundleInstaller.installBundle("extendable.tb1"); //$NON-NLS-1$
26
		bundle.start();
27
	}
28
29
	public void testExtensions() {
30
		EquinoxMetaTypeInformation mti = metatype.getMetaTypeInformation(bundle);
31
		EquinoxObjectClassDefinition ocd = mti.getObjectClassDefinition("metatype.extendable.tb1.1", null); //$NON-NLS-1$
32
		Set schemas = ocd.getExtensionUris();
33
		assertNotNull("Null extension schemas", schemas); //$NON-NLS-1$
34
		assertEquals("Wrong schemas size", 2, schemas.size()); //$NON-NLS-1$
35
		assertTrue("Missing schema", schemas.contains("urn:xmlns:foo")); //$NON-NLS-1$ //$NON-NLS-2$
36
		assertTrue("Missing schema", schemas.contains("urn:xmlns:validation")); //$NON-NLS-1$ //$NON-NLS-2$
37
		Map attributes = ocd.getExtensionAttributes("urn:xmlns:foo"); //$NON-NLS-1$
38
		assertNotNull("Null attributes", attributes); //$NON-NLS-1$
39
		assertEquals("Wrong attributes size", 1, attributes.size()); //$NON-NLS-1$
40
		assertEquals("Wrong value", "bar", attributes.get("foo")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
41
		attributes = ocd.getExtensionAttributes("urn:xmlns:validation"); //$NON-NLS-1$
42
		assertNotNull("Null attributes", attributes); //$NON-NLS-1$
43
		assertEquals("Wrong attributes size", 1, attributes.size()); //$NON-NLS-1$
44
		assertEquals("Wrong value", "true", attributes.get("enabled")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
45
		EquinoxAttributeDefinition[] ads = ocd.getAttributeDefinitions(ObjectClassDefinition.ALL);
46
		for (int i = 0; i < ads.length; i++) {
47
			if (ads[i].getID().equals("ad1")) { //$NON-NLS-1$
48
				schemas = ads[i].getExtensionUris();
49
				assertNotNull("Null extension schemas", schemas); //$NON-NLS-1$
50
				assertEquals("Wrong schemas size", 2, schemas.size()); //$NON-NLS-1$
51
				assertTrue("Missing schema", schemas.contains("urn:xmlns:foo")); //$NON-NLS-1$ //$NON-NLS-2$
52
				assertTrue("Missing schema", schemas.contains("urn:xmlns:validation")); //$NON-NLS-1$ //$NON-NLS-2$
53
				attributes = ads[i].getExtensionAttributes("urn:xmlns:foo"); //$NON-NLS-1$
54
				assertNotNull("Null attributes", attributes); //$NON-NLS-1$
55
				assertEquals("Wrong attributes size", 1, attributes.size()); //$NON-NLS-1$
56
				assertEquals("Wrong value", "foo", attributes.get("bar")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
57
				attributes = ads[i].getExtensionAttributes("urn:xmlns:validation"); //$NON-NLS-1$
58
				assertNotNull("Null attributes", attributes); //$NON-NLS-1$
59
				assertEquals("Wrong attributes size", 2, attributes.size()); //$NON-NLS-1$
60
				assertEquals("Wrong value", "[a-zA-Z0-9]", attributes.get("regexp")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
61
				assertEquals("Wrong value", "validation", attributes.get("validation")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
62
			}
63
		}
64
	}
65
}
(-).settings/.api_filters (-11 lines)
Removed Link Here
1
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
<component id="org.eclipse.equinox.metatype" version="2">
3
    <resource path="src/org/eclipse/equinox/metatype/LogTracker.java" type="org.eclipse.equinox.metatype.LogTracker">
4
        <filter id="574619656">
5
            <message_arguments>
6
                <message_argument value="LogService"/>
7
                <message_argument value="LogTracker"/>
8
            </message_arguments>
9
        </filter>
10
    </resource>
11
</component>
(-)META-INF/MANIFEST.MF (-3 / +4 lines)
Lines 1-8 Link Here
1
Bundle-ManifestVersion: 2
1
Bundle-ManifestVersion: 2
2
Bundle-Name: %bundleName
2
Bundle-Name: %bundleName
3
Bundle-Version: 1.1.100.qualifier
3
Bundle-Version: 1.2.0.qualifier
4
Bundle-SymbolicName: org.eclipse.equinox.metatype
4
Bundle-SymbolicName: org.eclipse.equinox.metatype
5
Bundle-Activator: org.eclipse.equinox.metatype.Activator
5
Bundle-Activator: org.eclipse.equinox.metatype.impl.Activator
6
Import-Package: javax.xml.parsers,
6
Import-Package: javax.xml.parsers,
7
 org.eclipse.osgi.util;version="[1.1,2.0)",
7
 org.eclipse.osgi.util;version="[1.1,2.0)",
8
 org.osgi.framework;version="[1.6,2.0)",
8
 org.osgi.framework;version="[1.6,2.0)",
Lines 13-19 Link Here
13
 org.osgi.util.tracker;version="[1.5,2.0)",
13
 org.osgi.util.tracker;version="[1.5,2.0)",
14
 org.xml.sax,
14
 org.xml.sax,
15
 org.xml.sax.helpers
15
 org.xml.sax.helpers
16
Export-Package: org.eclipse.equinox.metatype;x-internal:=true
16
Export-Package: org.eclipse.equinox.metatype;version="1.2.0",
17
 org.eclipse.equinox.metatype.impl;version="1.2.0";x-internal:=true
17
Bundle-Vendor: %bundleVendor
18
Bundle-Vendor: %bundleVendor
18
Bundle-Localization: plugin
19
Bundle-Localization: plugin
19
Bundle-RequiredExecutionEnvironment: J2SE-1.5,
20
Bundle-RequiredExecutionEnvironment: J2SE-1.5,
(-)src/org/eclipse/equinox/metatype/Activator.java (-188 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype;
12
13
import java.util.Dictionary;
14
import java.util.Hashtable;
15
import javax.xml.parsers.SAXParserFactory;
16
import org.osgi.framework.*;
17
import org.osgi.service.cm.ManagedService;
18
import org.osgi.service.log.LogService;
19
import org.osgi.service.metatype.MetaTypeProvider;
20
import org.osgi.service.metatype.MetaTypeService;
21
import org.osgi.util.tracker.ServiceTracker;
22
import org.osgi.util.tracker.ServiceTrackerCustomizer;
23
24
/**
25
 * MetaType Activator
26
 */
27
public class Activator implements BundleActivator {
28
	/*
29
	 * The following filter guarantees only services meeting the following
30
	 * criteria will be tracked.
31
	 * 
32
	 * (1) A ManagedService or ManagedServiceFactory registered with a
33
	 * SERVICE_PID property. May also be registered as a MetaTypeProvider.
34
	 * (2) A MetaTypeProvider registered with a METATYPE_PID or
35
	 * METATYPE_FACTORY_PID property.
36
	 * 
37
	 * Note that it's still necessary to inspect a ManagedService or
38
	 * ManagedServiceFactory to ensure it also implements MetaTypeProvider.
39
	 */
40
	private static final String FILTER = "(|(&(" + Constants.OBJECTCLASS + '=' + ManagedService.class.getName() + "*)(" + Constants.SERVICE_PID + "=*))(&(" + Constants.OBJECTCLASS + '=' + MetaTypeProvider.class.getName() + ")(|(" + MetaTypeProvider.METATYPE_PID + "=*)(" + MetaTypeProvider.METATYPE_FACTORY_PID + "=*))))"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
41
	private static final String SERVICE_PID = "org.osgi.impl.service.metatype.MetaTypeService"; //$NON-NLS-1$
42
43
	private LogTracker logServiceTracker;
44
	// Could be ManagedService, ManagedServiceFactory, or MetaTypeProvider.
45
	// The tracker tracks all services regardless of bundle. Services are
46
	// filtered by bundle later in the MetaTypeProviderTracker class. It may 
47
	// therefore be shared among multiple instances of that class.
48
	private ServiceTracker<Object, Object> metaTypeProviderTracker;
49
	private ServiceTracker<SAXParserFactory, SAXParserFactory> saxParserFactoryTracker;
50
51
	public void start(BundleContext context) throws InvalidSyntaxException {
52
		LogTracker lsTracker;
53
		ServiceTracker<Object, Object> mtpTracker;
54
		ServiceTracker<SAXParserFactory, SAXParserFactory> spfTracker;
55
		Filter filter = context.createFilter(FILTER);
56
		synchronized (this) {
57
			lsTracker = logServiceTracker = new LogTracker(context, System.out);
58
			mtpTracker = metaTypeProviderTracker = new ServiceTracker<Object, Object>(context, filter, null);
59
			spfTracker = saxParserFactoryTracker = new ServiceTracker<SAXParserFactory, SAXParserFactory>(context, SAXParserFactory.class, new SAXParserFactoryTrackerCustomizer(context, lsTracker, mtpTracker));
60
		}
61
		// Do this first to make logging available as early as possible.
62
		lsTracker.open();
63
		lsTracker.log(LogService.LOG_DEBUG, "====== Meta Type Service starting ! ====="); //$NON-NLS-1$
64
		// Do this next to make MetaTypeProviders available as early as possible.
65
		mtpTracker.open();
66
		// Do this last because it may result in the MetaTypeService being registered.
67
		spfTracker.open();
68
	}
69
70
	public void stop(BundleContext context) {
71
		ServiceTracker<SAXParserFactory, SAXParserFactory> spfTracker;
72
		ServiceTracker<Object, Object> mtpTracker;
73
		LogTracker lsTracker;
74
		synchronized (this) {
75
			spfTracker = saxParserFactoryTracker;
76
			// Set this to null so the SAXParserFactoryTrackerCustomizer knows
77
			// not to register a new MetaTypeService when removedService() is
78
			// called while the tracker is closing.
79
			saxParserFactoryTracker = null;
80
			mtpTracker = metaTypeProviderTracker;
81
			lsTracker = logServiceTracker;
82
		}
83
		lsTracker.log(LogService.LOG_DEBUG, "====== Meta Type Service stopping ! ====="); //$NON-NLS-1$
84
		spfTracker.close();
85
		mtpTracker.close();
86
		// Do this last to leave logging available as long as possible.
87
		lsTracker.close();
88
	}
89
90
	synchronized ServiceTracker<SAXParserFactory, SAXParserFactory> getSAXParserFactoryTracker() {
91
		return saxParserFactoryTracker;
92
	}
93
94
	private class SAXParserFactoryTrackerCustomizer implements ServiceTrackerCustomizer<SAXParserFactory, SAXParserFactory> {
95
		private final BundleContext bundleCtx;
96
		private final LogService logService;
97
		private final ServiceTracker<Object, Object> mtpTracker;
98
99
		private MetaTypeServiceImpl metaTypeService;
100
		private ServiceRegistration<MetaTypeService> metaTypeServiceRegistration;
101
		private SAXParserFactory saxParserFactory;
102
103
		public SAXParserFactoryTrackerCustomizer(BundleContext bundleContext, LogService logService, ServiceTracker<Object, Object> metaTypeProviderTracker) {
104
			this.bundleCtx = bundleContext;
105
			this.logService = logService;
106
			this.mtpTracker = metaTypeProviderTracker;
107
		}
108
109
		public SAXParserFactory addingService(ServiceReference<SAXParserFactory> ref) {
110
			SAXParserFactory parserFactory = bundleCtx.getService(ref);
111
			if (parserFactory == null)
112
				return null;
113
			boolean register = false;
114
			synchronized (this) {
115
				if (saxParserFactory == null) {
116
					// Save this parserFactory as the currently used parserFactory
117
					saxParserFactory = parserFactory;
118
					register = true;
119
				}
120
			}
121
			if (register) {
122
				registerMetaTypeService();
123
			}
124
			return parserFactory;
125
		}
126
127
		public void modifiedService(ServiceReference<SAXParserFactory> ref, SAXParserFactory object) {
128
			// noop
129
		}
130
131
		public void removedService(ServiceReference<SAXParserFactory> ref, SAXParserFactory object) {
132
			ServiceRegistration<MetaTypeService> registration = null;
133
			MetaTypeServiceImpl service = null;
134
			synchronized (this) {
135
				if (object == saxParserFactory) {
136
					// This means that this SAXParserFactory was used to start the
137
					// MetaTypeService. Set to null to indicate a new MetaTypeService
138
					// needs to be registered.
139
					saxParserFactory = null;
140
					registration = metaTypeServiceRegistration;
141
					service = metaTypeService;
142
				}
143
			}
144
			if (registration != null) {
145
				registration.unregister();
146
				bundleCtx.removeBundleListener(service);
147
				// See if another factory is available
148
				ServiceTracker<SAXParserFactory, SAXParserFactory> tracker = getSAXParserFactoryTracker();
149
				// If the SAXParserFactory tracker is null, the bundle is stopping, and we
150
				// shouldn't register a new MetaTypeService to avoid unnecessary churn.
151
				if (tracker != null) {
152
					SAXParserFactory factory = tracker.getService();
153
					if (factory != null) {
154
						// We have another parser so lets restart the MetaTypeService
155
						boolean register = false;
156
						synchronized (this) {
157
							if (saxParserFactory == null) {
158
								saxParserFactory = factory;
159
								register = true;
160
							}
161
						}
162
						if (register) {
163
							registerMetaTypeService();
164
						}
165
					}
166
				}
167
			}
168
			bundleCtx.ungetService(ref);
169
		}
170
171
		private void registerMetaTypeService() {
172
			Dictionary<String, Object> properties = new Hashtable<String, Object>(7);
173
			properties = new Hashtable<String, Object>(7);
174
			properties.put(Constants.SERVICE_VENDOR, "IBM"); //$NON-NLS-1$
175
			properties.put(Constants.SERVICE_DESCRIPTION, MetaTypeMsg.SERVICE_DESCRIPTION);
176
			properties.put(Constants.SERVICE_PID, SERVICE_PID);
177
			MetaTypeServiceImpl service;
178
			synchronized (this) {
179
				service = metaTypeService = new MetaTypeServiceImpl(saxParserFactory, logService, mtpTracker);
180
			}
181
			bundleCtx.addBundleListener(service);
182
			ServiceRegistration<MetaTypeService> registration = bundleCtx.registerService(MetaTypeService.class, service, properties);
183
			synchronized (this) {
184
				metaTypeServiceRegistration = registration;
185
			}
186
		}
187
	}
188
}
(-)src/org/eclipse/equinox/metatype/AttributeDefinitionImpl.java (-298 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype;
12
13
import java.util.Enumeration;
14
import java.util.Vector;
15
import org.eclipse.osgi.util.NLS;
16
import org.osgi.service.log.LogService;
17
import org.osgi.service.metatype.AttributeDefinition;
18
19
/**
20
 * Implementation of AttributeDefintion
21
 */
22
public class AttributeDefinitionImpl extends LocalizationElement implements AttributeDefinition, Cloneable {
23
24
	String _name;
25
	String _id;
26
	String _description;
27
	int _cardinality = 0;
28
	int _dataType;
29
	Object _minValue = null;
30
	Object _maxValue = null;
31
	boolean _isRequired = true;
32
33
	String[] _defaults = null;
34
	Vector<String> _values = new Vector<String>(7);
35
	Vector<String> _labels = new Vector<String>(7);
36
37
	private final LogService logger;
38
39
	/**
40
	 * Constructor of class AttributeDefinitionImpl.
41
	 */
42
	public AttributeDefinitionImpl(String id, String name, String description, int type, int cardinality, Object min, Object max, boolean isRequired, String localization, LogService logger) {
43
44
		this._id = id;
45
		this._name = name;
46
		this._description = description;
47
		this._dataType = type;
48
		this._cardinality = cardinality;
49
		this._minValue = min;
50
		this._maxValue = max;
51
		this._isRequired = isRequired;
52
		this._localization = localization;
53
		this.logger = logger;
54
	}
55
56
	/*
57
	 * 
58
	 */
59
	public synchronized Object clone() {
60
61
		AttributeDefinitionImpl ad = new AttributeDefinitionImpl(_id, _name, _description, _dataType, _cardinality, _minValue, _maxValue, _isRequired, _localization, logger);
62
63
		if (_defaults != null) {
64
			ad.setDefaultValue(_defaults.clone());
65
		}
66
		if ((_labels != null) && (_values != null)) {
67
			@SuppressWarnings("unchecked")
68
			Vector<String> labels = (Vector<String>) _labels.clone();
69
			@SuppressWarnings("unchecked")
70
			Vector<String> values = (Vector<String>) _values.clone();
71
			ad.setOption(labels, values, false);
72
		}
73
74
		return ad;
75
	}
76
77
	/*
78
	 * (non-Javadoc)
79
	 * 
80
	 * @see org.osgi.service.metatype.AttributeDefinition#getName()
81
	 */
82
	public String getName() {
83
		return getLocalized(_name);
84
	}
85
86
	/**
87
	 * Method to set the name of AttributeDefinition.
88
	 */
89
	void setName(String name) {
90
		this._name = name;
91
	}
92
93
	/*
94
	 * (non-Javadoc)
95
	 * 
96
	 * @see org.osgi.service.metatype.AttributeDefinition#getID()
97
	 */
98
	public String getID() {
99
		return _id;
100
	}
101
102
	/**
103
	 * Method to set the ID of AttributeDefinition.
104
	 */
105
	void setID(String id) {
106
		this._id = id;
107
	}
108
109
	/*
110
	 * (non-Javadoc)
111
	 * 
112
	 * @see org.osgi.service.metatype.AttributeDefinition#getDescription()
113
	 */
114
	public String getDescription() {
115
		return getLocalized(_description);
116
	}
117
118
	/**
119
	 * Method to set the description of AttributeDefinition.
120
	 */
121
	void setDescription(String description) {
122
		this._description = description;
123
	}
124
125
	/*
126
	 * (non-Javadoc)
127
	 * 
128
	 * @see org.osgi.service.metatype.AttributeDefinition#getCardinality()
129
	 */
130
	public int getCardinality() {
131
		return _cardinality;
132
	}
133
134
	/**
135
	 * Method to set the cardinality of AttributeDefinition.
136
	 */
137
	void setCardinality(int cardinality) {
138
		this._cardinality = cardinality;
139
	}
140
141
	/*
142
	 * (non-Javadoc)
143
	 * 
144
	 * @see org.osgi.service.metatype.AttributeDefinition#getType()
145
	 */
146
	public int getType() {
147
		return _dataType;
148
	}
149
150
	/**
151
	 * Method to set the data type of AttributeDefinition.
152
	 */
153
	void setType(int type) {
154
		this._dataType = type;
155
	}
156
157
	/**
158
	 * Method to get the required flag of AttributeDefinition.
159
	 */
160
	boolean isRequired() {
161
		return _isRequired;
162
	}
163
164
	/**
165
	 * Method to set the required flag of AttributeDefinition.
166
	 */
167
	void setRequired(boolean isRequired) {
168
		this._isRequired = isRequired;
169
	}
170
171
	/*
172
	 * (non-Javadoc)
173
	 * 
174
	 * @see org.osgi.service.metatype.AttributeDefinition#getOptionLabels()
175
	 */
176
	public String[] getOptionLabels() {
177
178
		if ((_labels == null) || (_labels.size() == 0)) {
179
			return null;
180
		}
181
182
		String[] returnedLabels = new String[_labels.size()];
183
		Enumeration<String> labelKeys = _labels.elements();
184
		int i = 0;
185
		while (labelKeys.hasMoreElements()) {
186
			String labelKey = labelKeys.nextElement();
187
			returnedLabels[i] = getLocalized(labelKey);
188
			i++;
189
		}
190
		return returnedLabels;
191
	}
192
193
	/*
194
	 * (non-Javadoc)
195
	 * 
196
	 * @see org.osgi.service.metatype.AttributeDefinition#getOptionValues()
197
	 */
198
	public String[] getOptionValues() {
199
200
		if ((_values == null) || (_values.size() == 0)) {
201
			return null;
202
		}
203
204
		return _values.toArray(new String[_values.size()]);
205
	}
206
207
	/**
208
	 * Method to set the Option values of AttributeDefinition.
209
	 */
210
	void setOption(Vector<String> labels, Vector<String> values, boolean needValidation) {
211
		if ((labels == null) || (values == null)) {
212
			logger.log(LogService.LOG_ERROR, "AttributeDefinitionImpl.setOption(Vector, Vector, boolean) " + MetaTypeMsg.NULL_OPTIONS); //$NON-NLS-1$
213
			return;
214
		}
215
		if (labels.size() != values.size()) {
216
			logger.log(LogService.LOG_ERROR, "AttributeDefinitionImpl.setOption(Vector, Vector, boolean) " + MetaTypeMsg.INCONSISTENT_OPTIONS); //$NON-NLS-1$
217
			return;
218
		}
219
		_labels = labels;
220
		_values = values;
221
		if (needValidation) {
222
			for (int index = 0; index < _values.size(); index++) {
223
				ValueTokenizer vt = new ValueTokenizer(_values.get(index), logger);
224
				_values.set(index, vt.getValuesAsString());
225
				String reason = vt.validate(this);
226
				if ((reason != null) && reason.length() > 0) {
227
					logger.log(LogService.LOG_WARNING, NLS.bind(MetaTypeMsg.INVALID_OPTIONS, _values.get(index), reason));
228
					_labels.remove(index);
229
					_values.remove(index);
230
					index--; // Because this one has been removed.
231
				}
232
			}
233
		}
234
	}
235
236
	/*
237
	 * (non-Javadoc)
238
	 * 
239
	 * @see org.osgi.service.metatype.AttributeDefinition#getDefaultValue()
240
	 */
241
	public String[] getDefaultValue() {
242
		return _defaults;
243
	}
244
245
	/**
246
	 * Method to set the default value of AttributeDefinition.
247
	 * The given parameter is a comma delimited list needed to be parsed.
248
	 */
249
	void setDefaultValue(String defaults_str, boolean needValidation) {
250
		ValueTokenizer vt = new ValueTokenizer(defaults_str, logger);
251
		String reason = vt.validate(this);
252
		if ((reason != null) && reason.length() > 0) {
253
			logger.log(LogService.LOG_WARNING, NLS.bind(MetaTypeMsg.INVALID_DEFAULTS, vt.getValuesAsString(), reason));
254
			return;
255
		}
256
		setDefaultValue(vt.getValuesAsArray());
257
	}
258
259
	/**
260
	 * Method to set the default value of AttributeDefinition.
261
	 * The given parameter is a String array of multi values.
262
	 */
263
	void setDefaultValue(String[] defaults) {
264
		_defaults = defaults;
265
	}
266
267
	/**
268
	 * Method to set the validation value - min of AttributeDefinition.
269
	 */
270
	void setMinValue(Object minValue) {
271
		this._minValue = minValue;
272
	}
273
274
	/**
275
	 * Method to set the validation value - max of AttributeDefinition.
276
	 */
277
	void setMaxValue(Object maxValue) {
278
		this._maxValue = maxValue;
279
	}
280
281
	/*
282
	 * (non-Javadoc)
283
	 * In order to be valid, a value must pass all of the following tests.
284
	 * (1) The value must not be null.
285
	 * (2) The value must be convertible into the attribute definition's type.
286
	 * (3) The following relation must hold: min <= value <= max, if either min or max was specified.
287
	 * (4) If options were specified, the value must be equal to one of them.
288
	 * 
289
	 * Note this method will never return null to indicate there's no validation
290
	 * present. The type compatibility check can always be performed.
291
	 * 
292
	 * @see org.osgi.service.metatype.AttributeDefinition#validate(java.lang.String)
293
	 */
294
	public String validate(String value) {
295
		ValueTokenizer vt = new ValueTokenizer(value, logger);
296
		return vt.validate(this);
297
	}
298
}
(-)src/org/eclipse/equinox/metatype/DataParser.java (-841 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype;
12
13
import java.io.*;
14
import java.math.BigDecimal;
15
import java.math.BigInteger;
16
import java.net.URL;
17
import java.util.*;
18
import javax.xml.parsers.*;
19
import org.eclipse.osgi.util.NLS;
20
import org.osgi.framework.Bundle;
21
import org.osgi.service.log.LogService;
22
import org.osgi.service.metatype.AttributeDefinition;
23
import org.xml.sax.*;
24
import org.xml.sax.helpers.DefaultHandler;
25
26
/**
27
 * Meta XML Data Parser
28
 */
29
public class DataParser {
30
	private static final String METADATA = "MetaData"; //$NON-NLS-1$
31
	private static final String LOCALIZATION = "localization"; //$NON-NLS-1$
32
	private static final String OCD = "OCD"; //$NON-NLS-1$
33
	private static final String ICON = "Icon"; //$NON-NLS-1$
34
	private static final String AD = "AD"; //$NON-NLS-1$
35
	private static final String CARDINALITY = "cardinality"; //$NON-NLS-1$
36
	private static final String OPTION = "Option"; //$NON-NLS-1$
37
	private static final String LABEL = "label"; //$NON-NLS-1$
38
	private static final String VALUE = "value"; //$NON-NLS-1$
39
	private static final String MIN = "min"; //$NON-NLS-1$
40
	private static final String MAX = "max"; //$NON-NLS-1$
41
	private static final String TYPE = "type"; //$NON-NLS-1$
42
	private static final String SIZE = "size"; //$NON-NLS-1$
43
	private static final String ID = "id"; //$NON-NLS-1$
44
	private static final String NAME = "name"; //$NON-NLS-1$
45
	private static final String DESCRIPTION = "description"; //$NON-NLS-1$
46
	private static final String RESOURCE = "resource"; //$NON-NLS-1$
47
	private static final String PID = "pid"; //$NON-NLS-1$
48
	private static final String DEFAULT = "default"; //$NON-NLS-1$
49
	private static final String ADREF = "adref"; //$NON-NLS-1$
50
	private static final String CONTENT = "content"; //$NON-NLS-1$
51
	private static final String FACTORY = "factoryPid"; //$NON-NLS-1$
52
	private static final String BUNDLE = "bundle"; //$NON-NLS-1$
53
	private static final String OPTIONAL = "optional"; //$NON-NLS-1$
54
	private static final String OBJECT = "Object"; //$NON-NLS-1$
55
	private static final String OCDREF = "ocdref"; //$NON-NLS-1$
56
	private static final String ATTRIBUTE = "Attribute"; //$NON-NLS-1$
57
	private static final String DESIGNATE = "Designate"; //$NON-NLS-1$
58
	private static final String MERGE = "merge"; //$NON-NLS-1$
59
	private static final String REQUIRED = "required"; //$NON-NLS-1$
60
61
	private static final String INTEGER = "Integer"; //$NON-NLS-1$
62
	private static final String STRING = "String"; //$NON-NLS-1$
63
	private static final String FLOAT = "Float"; //$NON-NLS-1$
64
	private static final String DOUBLE = "Double"; //$NON-NLS-1$
65
	private static final String BYTE = "Byte"; //$NON-NLS-1$
66
	private static final String LONG = "Long"; //$NON-NLS-1$
67
	private static final String CHAR = "Char"; //$NON-NLS-1$
68
	private static final String BOOLEAN = "Boolean"; //$NON-NLS-1$
69
	private static final String SHORT = "Short"; //$NON-NLS-1$
70
	private static final String PASSWORD = "Password"; //$NON-NLS-1$
71
72
	protected Bundle _dp_bundle;
73
	protected URL _dp_url;
74
	protected SAXParserFactory _dp_parserFactory;
75
	protected XMLReader _dp_xmlReader;
76
77
	// DesignateHanders in DataParser class
78
	Vector<DesignateHandler> _dp_designateHandlers = new Vector<DesignateHandler>(7);
79
	// ObjectClassDefinitions in DataParser class w/ corresponding reference keys
80
	Hashtable<String, ObjectClassDefinitionImpl> _dp_OCDs = new Hashtable<String, ObjectClassDefinitionImpl>(7);
81
	// Localization in DataParser class
82
	String _dp_localization;
83
84
	// Default visibility to avoid a plethora of synthetic accessor method warnings.
85
	final LogService logger;
86
	final Collection<Designate> designates = new ArrayList<Designate>(7);
87
88
	/*
89
	 * Constructor of class DataParser.
90
	 */
91
	public DataParser(Bundle bundle, URL url, SAXParserFactory parserFactory, LogService logger) {
92
93
		this._dp_bundle = bundle;
94
		this._dp_url = url;
95
		this._dp_parserFactory = parserFactory;
96
		parserFactory.setValidating(false);
97
		this.logger = logger;
98
	}
99
100
	/*
101
	 * Main method to parse specific MetaData file.
102
	 */
103
	public Collection<Designate> doParse() throws IOException, ParserConfigurationException, SAXException {
104
		SAXParser saxParser = _dp_parserFactory.newSAXParser();
105
		_dp_xmlReader = saxParser.getXMLReader();
106
		_dp_xmlReader.setContentHandler(new RootHandler());
107
		_dp_xmlReader.setErrorHandler(new MyErrorHandler(System.err));
108
		InputStream is = _dp_url.openStream();
109
		InputSource isource = new InputSource(is);
110
		logger.log(LogService.LOG_DEBUG, "Starting to parse " + _dp_url); //$NON-NLS-1$					
111
		_dp_xmlReader.parse(isource);
112
		return designates;
113
	}
114
115
	/*
116
	 * Convert String for expected data type.
117
	 */
118
	static Object convert(String value, int type) {
119
120
		if (value == null) {
121
			return null;
122
		}
123
124
		switch (type) {
125
		// PASSWORD should be treated like STRING.
126
			case AttributeDefinition.PASSWORD :
127
			case AttributeDefinition.STRING :
128
				// Both the min and max of STRING are Integers.
129
				return new Integer(value);
130
			case AttributeDefinition.LONG :
131
				return new Long(value);
132
			case AttributeDefinition.INTEGER :
133
				return new Integer(value);
134
			case AttributeDefinition.SHORT :
135
				return new Short(value);
136
			case AttributeDefinition.CHARACTER :
137
				return new Character(value.charAt(0));
138
			case AttributeDefinition.BYTE :
139
				return new Byte(value);
140
			case AttributeDefinition.DOUBLE :
141
				return new Double(value);
142
			case AttributeDefinition.FLOAT :
143
				return new Float(value);
144
			case AttributeDefinition.BIGINTEGER :
145
				return new BigInteger(value);
146
			case AttributeDefinition.BIGDECIMAL :
147
				return new BigDecimal(value);
148
			case AttributeDefinition.BOOLEAN :
149
				return new Boolean(value);
150
			default :
151
				// Unknown data type
152
				return null;
153
		}
154
	}
155
156
	/**
157
	 * Abstract of all Handlers.
158
	 */
159
	private class AbstractHandler extends DefaultHandler {
160
161
		protected ContentHandler _doc_handler;
162
		protected boolean _isParsedDataValid = true;
163
164
		public AbstractHandler(ContentHandler parentHandler) {
165
166
			this._doc_handler = parentHandler;
167
			_dp_xmlReader.setContentHandler(this);
168
		}
169
170
		public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
171
172
			throw new SAXException(NLS.bind(MetaTypeMsg.UNEXPECTED_ELEMENT, qName));
173
		}
174
175
		public void characters(char[] buf, int start, int end) throws SAXException {
176
177
			String s = new String(buf, start, end).trim();
178
			if (s.length() > 0) {
179
				throw new SAXException(NLS.bind(MetaTypeMsg.UNEXPECTED_TEXT, s));
180
			}
181
		}
182
183
		/**
184
		 * Called when this element and all elements nested into it have been
185
		 * handled.
186
		 */
187
		protected void finished() {
188
			// do nothing by default
189
		}
190
191
		public void endElement(String namespaceURI, String localName, String qName) {
192
193
			finished();
194
			// Let parent resume handling SAX events
195
			_dp_xmlReader.setContentHandler(_doc_handler);
196
		}
197
	}
198
199
	/**
200
	 * Handler for the root element.
201
	 */
202
	private class RootHandler extends DefaultHandler {
203
204
		public RootHandler() {
205
			super();
206
		}
207
208
		public void startElement(String uri, String localName, String qName, Attributes attributes) {
209
210
			logger.log(LogService.LOG_DEBUG, "Here is AbstractHandler:startElement():" //$NON-NLS-1$
211
					+ qName);
212
			String name = getName(localName, qName);
213
			if (name.equalsIgnoreCase(METADATA)) {
214
				new MetaDataHandler(this).init(name, attributes);
215
			} else {
216
				logger.log(LogService.LOG_WARNING, NLS.bind(MetaTypeMsg.UNEXPECTED_ELEMENT, name));
217
			}
218
		}
219
220
		public void setDocumentLocator(Locator locator) {
221
			// do nothing
222
		}
223
	}
224
225
	/**
226
	 * Handler for the MetaData element.
227
	 */
228
	private class MetaDataHandler extends AbstractHandler {
229
230
		public MetaDataHandler(ContentHandler handler) {
231
			super(handler);
232
		}
233
234
		public void init(String name, Attributes attributes) {
235
236
			logger.log(LogService.LOG_DEBUG, "Here is MetaDataHandler():init()"); //$NON-NLS-1$
237
			_dp_localization = attributes.getValue(LOCALIZATION);
238
			if (_dp_localization == null) {
239
				// Not a problem, because LOCALIZATION is an optional attribute.
240
			}
241
			// The global variable "_dp_localization" will be used within
242
			// OcdHandler and AttributeDefinitionHandler later.
243
		}
244
245
		public void startElement(String uri, String localName, String qName, Attributes atts) {
246
247
			logger.log(LogService.LOG_DEBUG, "Here is MetaDataHandler:startElement():" //$NON-NLS-1$
248
					+ qName);
249
			String name = getName(localName, qName);
250
			if (name.equalsIgnoreCase(DESIGNATE)) {
251
				DesignateHandler designateHandler = new DesignateHandler(this);
252
				designateHandler.init(name, atts);
253
				if (designateHandler._isParsedDataValid) {
254
					_dp_designateHandlers.addElement(designateHandler);
255
				}
256
			} else if (name.equalsIgnoreCase(OCD)) {
257
				OcdHandler ocdHandler = new OcdHandler(this);
258
				ocdHandler.init(name, atts, _dp_OCDs);
259
			} else {
260
				logger.log(LogService.LOG_WARNING, NLS.bind(MetaTypeMsg.UNEXPECTED_ELEMENT, name));
261
			}
262
		}
263
264
		protected void finished() {
265
266
			logger.log(LogService.LOG_DEBUG, "Here is MetaDataHandler():finished()"); //$NON-NLS-1$
267
			if (_dp_designateHandlers.size() == 0) {
268
				// Schema defines at least one DESIGNATE is required.
269
				_isParsedDataValid = false;
270
				logger.log(LogService.LOG_WARNING, "DataParser.finished() " + NLS.bind(MetaTypeMsg.MISSING_ELEMENT, DESIGNATE)); //$NON-NLS-1$
271
				return;
272
			}
273
			Enumeration<DesignateHandler> designateHandlerKeys = _dp_designateHandlers.elements();
274
			while (designateHandlerKeys.hasMoreElements()) {
275
				DesignateHandler dh = designateHandlerKeys.nextElement();
276
277
				ObjectClassDefinitionImpl ocd = _dp_OCDs.get(dh._ocdref);
278
				if (ocd != null) {
279
					designates.add(new Designate.Builder(ocd).bundle(dh._bundle_val).factoryPid(dh._factory_val).merge(dh._merge_val).pid(dh._pid_val).optional(dh._optional_val).build());
280
				} else {
281
					logger.log(LogService.LOG_ERROR, "DataParser.finished() " + NLS.bind(MetaTypeMsg.OCD_ID_NOT_FOUND, dh._ocdref)); //$NON-NLS-1$
282
283
				}
284
			}
285
		}
286
	}
287
288
	/**
289
	 * Handler for the ObjectClassDefinition element.
290
	 */
291
	private class OcdHandler extends AbstractHandler {
292
293
		Hashtable<String, ObjectClassDefinitionImpl> _parent_OCDs_hashtable;
294
		// This ID "_refID" is only used for reference by Designate element,
295
		// not the PID or FPID of this OCD.
296
		String _refID;
297
		ObjectClassDefinitionImpl _ocd;
298
		Vector<AttributeDefinitionImpl> _ad_vector = new Vector<AttributeDefinitionImpl>(7);
299
300
		public OcdHandler(ContentHandler handler) {
301
			super(handler);
302
		}
303
304
		public void init(String name, Attributes atts, Hashtable<String, ObjectClassDefinitionImpl> ocds_hashtable) {
305
306
			logger.log(LogService.LOG_DEBUG, "Here is OcdHandler():init()"); //$NON-NLS-1$
307
			_parent_OCDs_hashtable = ocds_hashtable;
308
309
			String ocd_name_val = atts.getValue(NAME);
310
			if (ocd_name_val == null) {
311
				_isParsedDataValid = false;
312
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes, Hashtable) " + NLS.bind(MetaTypeMsg.MISSING_ATTRIBUTE, NAME, name)); //$NON-NLS-1$
313
				return;
314
			}
315
316
			String ocd_description_val = atts.getValue(DESCRIPTION);
317
			if (ocd_description_val == null) {
318
				// Not a problem, because DESCRIPTION is an optional attribute.
319
			}
320
321
			_refID = atts.getValue(ID);
322
			if (_refID == null) {
323
				_isParsedDataValid = false;
324
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes, Hashtable) " + NLS.bind(MetaTypeMsg.MISSING_ATTRIBUTE, ID, name)); //$NON-NLS-1$
325
				return;
326
			}
327
328
			_ocd = new ObjectClassDefinitionImpl(ocd_name_val, ocd_description_val, _refID, _dp_localization);
329
		}
330
331
		public void startElement(String uri, String localName, String qName, Attributes atts) {
332
333
			logger.log(LogService.LOG_DEBUG, "Here is OcdHandler:startElement():" //$NON-NLS-1$
334
					+ qName);
335
			if (!_isParsedDataValid)
336
				return;
337
338
			String name = getName(localName, qName);
339
			if (name.equalsIgnoreCase(AD)) {
340
				AttributeDefinitionHandler attributeDefHandler = new AttributeDefinitionHandler(this);
341
				attributeDefHandler.init(name, atts, _ad_vector);
342
			} else if (name.equalsIgnoreCase(ICON)) {
343
				IconHandler iconHandler = new IconHandler(this);
344
				iconHandler.init(name, atts);
345
				if (iconHandler._isParsedDataValid) {
346
					// Because XML schema allows at most one icon for
347
					// one OCD, if more than one icons are read from 
348
					// MetaData, then only the final icon will be kept.
349
					_ocd.setIcon(iconHandler._icon);
350
				}
351
			} else {
352
				logger.log(LogService.LOG_WARNING, NLS.bind(MetaTypeMsg.UNEXPECTED_ELEMENT, name));
353
			}
354
		}
355
356
		protected void finished() {
357
358
			logger.log(LogService.LOG_DEBUG, "Here is OcdHandler():finished()"); //$NON-NLS-1$
359
			if (!_isParsedDataValid)
360
				return;
361
362
			if (_ad_vector.size() == 0) {
363
				// Schema defines at least one AD is required.
364
				_isParsedDataValid = false;
365
				logger.log(LogService.LOG_ERROR, "DataParser.finished() " + NLS.bind(MetaTypeMsg.MISSING_ELEMENT, AD, _refID)); //$NON-NLS-1$
366
				return;
367
			}
368
			// OCD gets all parsed ADs.
369
			Enumeration<AttributeDefinitionImpl> adKey = _ad_vector.elements();
370
			while (adKey.hasMoreElements()) {
371
				AttributeDefinitionImpl ad = adKey.nextElement();
372
				_ocd.addAttributeDefinition(ad, ad._isRequired);
373
			}
374
375
			_parent_OCDs_hashtable.put(_refID, _ocd);
376
		}
377
	}
378
379
	/**
380
	 * Handler for the Icon element.
381
	 */
382
	private class IconHandler extends AbstractHandler {
383
384
		Icon _icon;
385
386
		public IconHandler(ContentHandler handler) {
387
			super(handler);
388
		}
389
390
		public void init(String name, Attributes atts) {
391
392
			logger.log(LogService.LOG_DEBUG, "Here is IconHandler:init()"); //$NON-NLS-1$
393
			String icon_resource_val = atts.getValue(RESOURCE);
394
			if (icon_resource_val == null) {
395
				_isParsedDataValid = false;
396
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes) " + NLS.bind(MetaTypeMsg.MISSING_ATTRIBUTE, RESOURCE, name)); //$NON-NLS-1$
397
				return;
398
			}
399
400
			String icon_size_val = atts.getValue(SIZE);
401
			if (icon_size_val == null) {
402
				// Not a problem, because SIZE is an optional attribute.
403
				icon_size_val = "0"; //$NON-NLS-1$
404
			} else if (icon_size_val.equalsIgnoreCase("")) { //$NON-NLS-1$
405
				icon_size_val = "0"; //$NON-NLS-1$
406
			}
407
408
			_icon = new Icon(icon_resource_val, Integer.parseInt(icon_size_val), _dp_bundle);
409
		}
410
	}
411
412
	/**
413
	 * Handler for the Attribute element.
414
	 */
415
	private class AttributeDefinitionHandler extends AbstractHandler {
416
417
		AttributeDefinitionImpl _ad;
418
		int _dataType;
419
420
		Vector<AttributeDefinitionImpl> _parent_ADs_vector;
421
		Vector<String> _optionLabel_vector = new Vector<String>(7);
422
		Vector<String> _optionValue_vector = new Vector<String>(7);
423
424
		public AttributeDefinitionHandler(ContentHandler handler) {
425
			super(handler);
426
		}
427
428
		public void init(String name, Attributes atts, Vector<AttributeDefinitionImpl> ad_vector) {
429
430
			logger.log(LogService.LOG_DEBUG, "Here is AttributeDefinitionHandler():init()"); //$NON-NLS-1$
431
			_parent_ADs_vector = ad_vector;
432
433
			String ad_name_val = atts.getValue(NAME);
434
			if (ad_name_val == null) {
435
				// Not a problem, because NAME is an optional attribute.
436
			}
437
438
			String ad_description_val = atts.getValue(DESCRIPTION);
439
			if (ad_description_val == null) {
440
				// Not a problem, because DESCRIPTION is an optional attribute.
441
			}
442
443
			String ad_id_val = atts.getValue(ID);
444
			if (ad_id_val == null) {
445
				_isParsedDataValid = false;
446
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes, Vector) " + NLS.bind(MetaTypeMsg.MISSING_ATTRIBUTE, ID, name)); //$NON-NLS-1$
447
				return;
448
			}
449
450
			String ad_type_val = atts.getValue(TYPE);
451
			if (ad_type_val == null) {
452
				_isParsedDataValid = false;
453
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes, Vector) " + NLS.bind(MetaTypeMsg.MISSING_ATTRIBUTE, TYPE, name)); //$NON-NLS-1$
454
				return;
455
			}
456
			if (ad_type_val.equalsIgnoreCase(STRING)) {
457
				_dataType = AttributeDefinition.STRING;
458
			} else if (ad_type_val.equalsIgnoreCase(LONG)) {
459
				_dataType = AttributeDefinition.LONG;
460
			} else if (ad_type_val.equalsIgnoreCase(DOUBLE)) {
461
				_dataType = AttributeDefinition.DOUBLE;
462
			} else if (ad_type_val.equalsIgnoreCase(FLOAT)) {
463
				_dataType = AttributeDefinition.FLOAT;
464
			} else if (ad_type_val.equalsIgnoreCase(INTEGER)) {
465
				_dataType = AttributeDefinition.INTEGER;
466
			} else if (ad_type_val.equalsIgnoreCase(BYTE)) {
467
				_dataType = AttributeDefinition.BYTE;
468
			} else if (ad_type_val.equalsIgnoreCase(CHAR)) {
469
				_dataType = AttributeDefinition.CHARACTER;
470
			} else if (ad_type_val.equalsIgnoreCase(BOOLEAN)) {
471
				_dataType = AttributeDefinition.BOOLEAN;
472
			} else if (ad_type_val.equalsIgnoreCase(SHORT)) {
473
				_dataType = AttributeDefinition.SHORT;
474
			} else if (ad_type_val.equalsIgnoreCase(PASSWORD)) {
475
				_dataType = AttributeDefinition.PASSWORD;
476
			} else {
477
				_isParsedDataValid = false;
478
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes, Vector) " + NLS.bind(MetaTypeMsg.INVALID_TYPE, new Object[] {ad_type_val, _dp_url, _dp_bundle.getBundleId()})); //$NON-NLS-1$
479
				return;
480
			}
481
482
			String ad_cardinality_str = atts.getValue(CARDINALITY);
483
			int ad_cardinality_val = 0;
484
			if (ad_cardinality_str == null) {
485
				// Not a problem, because CARDINALITY is an optional attribute.
486
				// And the default value is 0.
487
			} else {
488
				ad_cardinality_val = Integer.parseInt(ad_cardinality_str);
489
			}
490
491
			String ad_min_val = atts.getValue(MIN);
492
			if (ad_min_val == null) {
493
				// Not a problem, because MIN is an optional attribute.
494
			}
495
496
			String ad_max_val = atts.getValue(MAX);
497
			if (ad_max_val == null) {
498
				// Not a problem, because MAX is an optional attribute.
499
			}
500
501
			String ad_defaults_str = atts.getValue(DEFAULT);
502
			if (ad_defaults_str == null) {
503
				// Not a problem, because DEFAULT is an optional attribute.
504
			}
505
506
			String ad_required_val = atts.getValue(REQUIRED);
507
			if (ad_required_val == null) {
508
				// Not a problem, because REQUIRED is an optional attribute.
509
				// And the default value is 'true'.
510
				ad_required_val = Boolean.TRUE.toString();
511
			}
512
513
			_ad = new AttributeDefinitionImpl(ad_id_val, ad_name_val, ad_description_val, _dataType, ad_cardinality_val, convert(ad_min_val, _dataType), convert(ad_max_val, _dataType), Boolean.valueOf(ad_required_val).booleanValue(), _dp_localization, logger);
514
515
			if (ad_defaults_str != null) {
516
				_ad.setDefaultValue(ad_defaults_str, true);
517
			}
518
		}
519
520
		public void startElement(String uri, String localName, String qName, Attributes atts) {
521
522
			logger.log(LogService.LOG_DEBUG, "Here is AttributeDefinitionHandler:startElement():" //$NON-NLS-1$
523
					+ qName);
524
			if (!_isParsedDataValid)
525
				return;
526
527
			String name = getName(localName, qName);
528
			if (name.equalsIgnoreCase(OPTION)) {
529
				OptionHandler optionHandler = new OptionHandler(this);
530
				optionHandler.init(name, atts);
531
				if (optionHandler._isParsedDataValid) {
532
					// Only add valid Option
533
					_optionLabel_vector.addElement(optionHandler._label_val);
534
					_optionValue_vector.addElement(optionHandler._value_val);
535
				}
536
			} else {
537
				logger.log(LogService.LOG_WARNING, NLS.bind(MetaTypeMsg.UNEXPECTED_ELEMENT, name));
538
			}
539
		}
540
541
		protected void finished() {
542
543
			logger.log(LogService.LOG_DEBUG, "Here is AttributeDefinitionHandler():finished()"); //$NON-NLS-1$
544
			if (!_isParsedDataValid)
545
				return;
546
547
			_ad.setOption(_optionLabel_vector, _optionValue_vector, true);
548
			_parent_ADs_vector.addElement(_ad);
549
		}
550
	}
551
552
	/**
553
	 * Handler for the Option element.
554
	 */
555
	private class OptionHandler extends AbstractHandler {
556
557
		String _label_val;
558
		String _value_val;
559
560
		public OptionHandler(ContentHandler handler) {
561
			super(handler);
562
		}
563
564
		public void init(String name, Attributes atts) {
565
566
			logger.log(LogService.LOG_DEBUG, "Here is OptionHandler:init()"); //$NON-NLS-1$
567
			_label_val = atts.getValue(LABEL);
568
			if (_label_val == null) {
569
				_isParsedDataValid = false;
570
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes) " + NLS.bind(MetaTypeMsg.MISSING_ATTRIBUTE, LABEL, name)); //$NON-NLS-1$
571
				return;
572
			}
573
574
			_value_val = atts.getValue(VALUE);
575
			if (_value_val == null) {
576
				_isParsedDataValid = false;
577
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes) " + NLS.bind(MetaTypeMsg.MISSING_ATTRIBUTE, VALUE, name)); //$NON-NLS-1$
578
				return;
579
			}
580
		}
581
	}
582
583
	//	/**
584
	//	 * Handler for the Simple Value element.
585
	//	 */
586
	//	private class SimpleValueHandler extends AbstractHandler {
587
	//
588
	//		StringBuffer	_buffer	= new StringBuffer();
589
	//		Vector			_parent_value_vector;
590
	//		String			_elementName;
591
	//
592
	//		public SimpleValueHandler(ContentHandler handler) {
593
	//			super(handler);
594
	//		}
595
	//
596
	//		public void init(String name, Attributes atts, Vector value_vector)
597
	//				throws SAXException {
598
	//
599
	//			Logging.log(LogService.LOG_DEBUG,
600
	//					"Here is SimpleValueHandler():init()"); //$NON-NLS-1$
601
	//			_elementName = name;
602
	//			_parent_value_vector = value_vector;
603
	//		}
604
	//
605
	//		protected void finished() throws SAXException {
606
	//
607
	//			Logging.log(LogService.LOG_DEBUG,
608
	//					"Here is SimpleValueHandler():finished()"); //$NON-NLS-1$
609
	//			if (_parent_value_vector != null) {
610
	//				_parent_value_vector.addElement(_buffer.toString());
611
	//			}
612
	//		}
613
	//
614
	//		public void characters(char buf[], int offset, int len)
615
	//				throws SAXException {
616
	//
617
	//			Logging.log(LogService.LOG_DEBUG,
618
	//					"Here is SimpleValueHandler(" //$NON-NLS-1$
619
	//					+ _elementName
620
	//					+ "):characters():[" //$NON-NLS-1$
621
	//					+ new String(buf, offset, len)
622
	//					+ "]"); //$NON-NLS-1$
623
	//			_buffer.append(new String(buf, offset, len));
624
	//		}
625
	//	}
626
627
	/**
628
	 * Handler for the Designate element.
629
	 */
630
	class DesignateHandler extends AbstractHandler {
631
632
		String _pid_val = null;
633
		String _factory_val = null;
634
		String _bundle_val = null; // Only used by RFC94
635
		boolean _optional_val = false; // Only used by RFC94
636
		boolean _merge_val = false; // Only used by RFC94
637
638
		// Referenced OCD ID
639
		String _ocdref;
640
641
		public DesignateHandler(ContentHandler handler) {
642
			super(handler);
643
		}
644
645
		public void init(String name, Attributes atts) {
646
647
			logger.log(LogService.LOG_DEBUG, "Here is DesignateHandler():init()"); //$NON-NLS-1$
648
			_pid_val = atts.getValue(PID);
649
			_factory_val = atts.getValue(FACTORY);
650
			if (_pid_val == null && _factory_val == null) {
651
				_isParsedDataValid = false;
652
				logger.log(LogService.LOG_ERROR, MetaTypeMsg.MISSING_DESIGNATE_PID_AND_FACTORYPID);
653
				return;
654
			}
655
656
			_bundle_val = atts.getValue(BUNDLE);
657
			if (_bundle_val == null) {
658
				// Not a problem because BUNDLE is an optional attribute.
659
			}
660
661
			String optional_str = atts.getValue(OPTIONAL);
662
			if (optional_str == null) {
663
				// Not a problem, because OPTIONAL is an optional attribute.
664
				// The default value is "false".
665
				_optional_val = false;
666
			} else {
667
				_optional_val = Boolean.valueOf(optional_str).booleanValue();
668
			}
669
670
			String merge_str = atts.getValue(MERGE);
671
			if (merge_str == null) {
672
				// Not a problem, because MERGE is an optional attribute.
673
				// The default value is "false".
674
				_merge_val = false;
675
			} else {
676
				_merge_val = Boolean.valueOf(merge_str).booleanValue();
677
			}
678
		}
679
680
		public void startElement(String uri, String localName, String qName, Attributes atts) {
681
682
			logger.log(LogService.LOG_DEBUG, "Here is DesignateHandler:startElement():" //$NON-NLS-1$
683
					+ qName);
684
			if (!_isParsedDataValid)
685
				return;
686
687
			String name = getName(localName, qName);
688
			if (name.equalsIgnoreCase(OBJECT)) {
689
				ObjectHandler objectHandler = new ObjectHandler(this);
690
				objectHandler.init(name, atts);
691
				if (objectHandler._isParsedDataValid) {
692
					_ocdref = objectHandler._ocdref;
693
				}
694
			} else {
695
				logger.log(LogService.LOG_WARNING, NLS.bind(MetaTypeMsg.UNEXPECTED_ELEMENT, name));
696
			}
697
		}
698
699
		protected void finished() {
700
701
			logger.log(LogService.LOG_DEBUG, "Here is DesignateHandler():finished()"); //$NON-NLS-1$
702
			if (!_isParsedDataValid)
703
				return;
704
705
			if (_ocdref == null) {
706
				_isParsedDataValid = false;
707
				// Schema defines at least one OBJECT is required.
708
				logger.log(LogService.LOG_ERROR, "DataParser.finished() " + NLS.bind(MetaTypeMsg.MISSING_ELEMENT, OBJECT, _pid_val)); //$NON-NLS-1$
709
				return;
710
711
			}
712
		}
713
	}
714
715
	/**
716
	 * Handler for the Object element.
717
	 */
718
	private class ObjectHandler extends AbstractHandler {
719
720
		String _ocdref;
721
722
		public ObjectHandler(ContentHandler handler) {
723
			super(handler);
724
		}
725
726
		public void init(String name, Attributes atts) {
727
728
			logger.log(LogService.LOG_DEBUG, "Here is ObjectHandler():init()"); //$NON-NLS-1$
729
			_ocdref = atts.getValue(OCDREF);
730
			if (_ocdref == null) {
731
				_isParsedDataValid = false;
732
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes) " + NLS.bind(MetaTypeMsg.MISSING_ATTRIBUTE, OCDREF, name)); //$NON-NLS-1$
733
				return;
734
			}
735
		}
736
737
		public void startElement(String uri, String localName, String qName, Attributes atts) {
738
739
			logger.log(LogService.LOG_DEBUG, "Here is ObjectHandler:startElement():" //$NON-NLS-1$
740
					+ qName);
741
			if (!_isParsedDataValid)
742
				return;
743
744
			String name = getName(localName, qName);
745
			if (name.equalsIgnoreCase(ATTRIBUTE)) {
746
				AttributeHandler attributeHandler = new AttributeHandler(this);
747
				attributeHandler.init(name, atts);
748
				// The ATTRIBUTE element is only used by RFC94, do nothing for it here.
749
			} else {
750
				logger.log(LogService.LOG_WARNING, NLS.bind(MetaTypeMsg.UNEXPECTED_ELEMENT, name));
751
			}
752
		}
753
	}
754
755
	/**
756
	 * Handler for the Attribute element.
757
	 * 
758
	 * This Handler is only used by RFC94.
759
	 */
760
	private class AttributeHandler extends AbstractHandler {
761
762
		String _adref_val;
763
		String _content_val;
764
765
		public AttributeHandler(ContentHandler handler) {
766
			super(handler);
767
		}
768
769
		public void init(String name, Attributes atts) {
770
771
			logger.log(LogService.LOG_DEBUG, "Here is AttributeHandler():init()"); //$NON-NLS-1$
772
			_adref_val = atts.getValue(ADREF);
773
			if (_adref_val == null) {
774
				_isParsedDataValid = false;
775
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes) " + NLS.bind(MetaTypeMsg.MISSING_ATTRIBUTE, ADREF, name)); //$NON-NLS-1$
776
				return;
777
			}
778
779
			_content_val = atts.getValue(CONTENT);
780
			if (_content_val == null) {
781
				_isParsedDataValid = false;
782
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes) " + NLS.bind(MetaTypeMsg.MISSING_ATTRIBUTE, CONTENT, name)); //$NON-NLS-1$
783
				return;
784
			}
785
		}
786
	}
787
788
	/**
789
	 * Error Handler to report errors and warnings
790
	 */
791
	private static class MyErrorHandler implements ErrorHandler {
792
793
		/** Error handler output goes here */
794
		private PrintStream _out;
795
796
		MyErrorHandler(PrintStream out) {
797
			this._out = out;
798
		}
799
800
		/**
801
		 * Returns a string describing parse exception details
802
		 */
803
		private String getParseExceptionInfo(SAXParseException spe) {
804
			String systemId = spe.getSystemId();
805
			if (systemId == null) {
806
				systemId = "null"; //$NON-NLS-1$
807
			}
808
			String info = "URI=" + systemId + //$NON-NLS-1$
809
					" Line=" + spe.getLineNumber() + //$NON-NLS-1$
810
					": " + spe.getMessage(); //$NON-NLS-1$
811
812
			return info;
813
		}
814
815
		// The following methods are standard SAX ErrorHandler methods.
816
		// See SAX documentation for more info.
817
818
		public void warning(SAXParseException spe) {
819
			_out.println("Warning: " + getParseExceptionInfo(spe)); //$NON-NLS-1$
820
		}
821
822
		public void error(SAXParseException spe) throws SAXException {
823
			String message = "Error: " + getParseExceptionInfo(spe); //$NON-NLS-1$
824
			throw new SAXException(message);
825
		}
826
827
		public void fatalError(SAXParseException spe) throws SAXException {
828
			String message = "Fatal Error: " + getParseExceptionInfo(spe); //$NON-NLS-1$
829
			throw new SAXException(message);
830
		}
831
	}
832
833
	public static String getName(String localName, String qName) {
834
		if (localName != null && localName.length() > 0) {
835
			return localName;
836
		}
837
838
		int nameSpaceIndex = qName.indexOf(":"); //$NON-NLS-1$
839
		return nameSpaceIndex == -1 ? qName : qName.substring(nameSpaceIndex + 1);
840
	}
841
}
(-)src/org/eclipse/equinox/metatype/Designate.java (-104 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype;
12
13
import org.eclipse.osgi.util.NLS;
14
15
public class Designate {
16
	public static class Builder {
17
		String bundle;
18
		String factoryPid;
19
		boolean merge;
20
		ObjectClassDefinitionImpl ocd;
21
		boolean optional;
22
		String pid;
23
24
		public Builder(ObjectClassDefinitionImpl ocd) {
25
			if (ocd == null) {
26
				throw new IllegalArgumentException(NLS.bind(MetaTypeMsg.MISSING_REQUIRED_PARAMETER, "ocd")); //$NON-NLS-1$
27
			}
28
			this.ocd = ocd;
29
		}
30
31
		public Designate build() {
32
			return new Designate(this);
33
		}
34
35
		public Builder bundle(String value) {
36
			bundle = value;
37
			return this;
38
		}
39
40
		public Builder factoryPid(String value) {
41
			factoryPid = value;
42
			return this;
43
		}
44
45
		public Builder merge(boolean value) {
46
			merge = value;
47
			return this;
48
		}
49
50
		public Builder optional(boolean value) {
51
			optional = value;
52
			return this;
53
		}
54
55
		public Builder pid(String value) {
56
			pid = value;
57
			return this;
58
		}
59
	}
60
61
	private final String bundle;
62
	private final String factoryPid;
63
	private final boolean merge;
64
	private final ObjectClassDefinitionImpl ocd;
65
	private final boolean optional;
66
	private final String pid;
67
68
	Designate(Builder b) {
69
		bundle = b.bundle;
70
		factoryPid = b.factoryPid;
71
		merge = b.merge;
72
		ocd = b.ocd;
73
		optional = b.optional;
74
		pid = b.pid;
75
	}
76
77
	public String getBundle() {
78
		return bundle;
79
	}
80
81
	public String getFactoryPid() {
82
		return factoryPid;
83
	}
84
85
	public boolean isFactory() {
86
		return factoryPid != null && factoryPid.length() != 0;
87
	}
88
89
	public boolean isMerge() {
90
		return merge;
91
	}
92
93
	public ObjectClassDefinitionImpl getObjectClassDefinition() {
94
		return ocd;
95
	}
96
97
	public boolean isOptional() {
98
		return optional;
99
	}
100
101
	public String getPid() {
102
		return pid;
103
	}
104
}
(-)src/org/eclipse/equinox/metatype/EquinoxAttributeDefinition.java (+19 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 IBM Corporation and others
3
 * All rights reserved. This program and the accompanying materials are made
4
 * available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 ******************************************************************************/
8
package org.eclipse.equinox.metatype;
9
10
import org.osgi.service.metatype.AttributeDefinition;
11
12
/**
13
 * 
14
 * @since 1.2
15
 *
16
 */
17
public interface EquinoxAttributeDefinition extends AttributeDefinition, Extendable {
18
	// Empty interface to support extendable attribute definitions.
19
}
(-)src/org/eclipse/equinox/metatype/EquinoxMetaTypeInformation.java (+19 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 IBM Corporation and others
3
 * All rights reserved. This program and the accompanying materials are made
4
 * available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 ******************************************************************************/
8
package org.eclipse.equinox.metatype;
9
10
import org.osgi.service.metatype.MetaTypeInformation;
11
12
/**
13
 * 
14
 * @since 1.2
15
 *
16
 */
17
public interface EquinoxMetaTypeInformation extends MetaTypeInformation {
18
	EquinoxObjectClassDefinition getObjectClassDefinition(String id, String locale);
19
}
(-)src/org/eclipse/equinox/metatype/EquinoxMetaTypeService.java (+20 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 IBM Corporation and others
3
 * All rights reserved. This program and the accompanying materials are made
4
 * available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 ******************************************************************************/
8
package org.eclipse.equinox.metatype;
9
10
import org.osgi.framework.Bundle;
11
import org.osgi.service.metatype.MetaTypeService;
12
13
/**
14
 * 
15
 * @since 1.2
16
 *
17
 */
18
public interface EquinoxMetaTypeService extends MetaTypeService {
19
	EquinoxMetaTypeInformation getMetaTypeInformation(Bundle bundle);
20
}
(-)src/org/eclipse/equinox/metatype/EquinoxObjectClassDefinition.java (+19 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 IBM Corporation and others
3
 * All rights reserved. This program and the accompanying materials are made
4
 * available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 ******************************************************************************/
8
package org.eclipse.equinox.metatype;
9
10
import org.osgi.service.metatype.ObjectClassDefinition;
11
12
/**
13
 * 
14
 * @since 1.2
15
 *
16
 */
17
public interface EquinoxObjectClassDefinition extends ObjectClassDefinition, Extendable {
18
	EquinoxAttributeDefinition[] getAttributeDefinitions(int filter);
19
}
(-)src/org/eclipse/equinox/metatype/Extendable.java (+22 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 IBM Corporation and others
3
 * All rights reserved. This program and the accompanying materials are made
4
 * available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 ******************************************************************************/
8
package org.eclipse.equinox.metatype;
9
10
import java.util.Map;
11
import java.util.Set;
12
13
/**
14
 * 
15
 * @since 1.2
16
 *
17
 */
18
public interface Extendable {
19
	Map<String, String> getExtensionAttributes(String uri);
20
21
	Set<String> getExtensionUris();
22
}
(-)src/org/eclipse/equinox/metatype/ExternalMessages.properties (-37 lines)
Removed Link Here
1
###############################################################################
2
# Copyright (c) 2005, 2011 IBM Corporation.
3
# All rights reserved. This program and the accompanying materials
4
# are made available under the terms of the Eclipse Public License v1.0
5
# which accompanies this distribution, and is available at
6
# http://www.eclipse.org/legal/epl-v10.html
7
#
8
# Contributors:
9
#     IBM Corporation - initial API and implementation
10
###############################################################################
11
#External Messages for EN locale
12
SERVICE_DESCRIPTION=OSGi Metatype Service - IBM Implementation
13
14
UNEXPECTED_ELEMENT=Unexpected element {0}.
15
UNEXPECTED_TEXT=Unexpected text {0}.
16
MISSING_ATTRIBUTE=Missing attribute {0} in tag {1}.
17
INVALID_TYPE=Invalid attribute definition type {0} in metadata XML at {1} for bundle ID {2}.
18
MISSING_DESIGNATE_PID_AND_FACTORYPID=A <Designate> element must specify either the 'pid' or 'factoryPid' attribute.
19
OCD_ID_NOT_FOUND=Object Class Definition ID not found {0}.
20
MISSING_ELEMENT=Missing element {0} (Reference ID = {1}.
21
22
EXCEPTION_MESSAGE=Unexpected exception {0} with message {1}.
23
NULL_IS_INVALID=Cannot validate a null.
24
VALUE_OUT_OF_RANGE=Value {0} is out of range.
25
VALUE_OUT_OF_OPTION=Value {0} is out of Option.
26
CARDINALITY_VIOLATION=Cardinality violation: \"{0}\" has {1} value(s) but must have between {2} and {3} value(s).
27
NULL_OPTIONS=Cannot set Option labels or values as null.
28
INCONSISTENT_OPTIONS=Labels and Values of Option have different sizes.
29
INVALID_OPTIONS=Option value {0} is invalid because of {1}.
30
INVALID_DEFAULTS=Dafaults value {0} is invalid because of {1}.
31
32
METADATA_NOT_FOUND=Bundle(ID=\"{0}\", name=\"{1}\") has no MetaData file.
33
ASK_INVALID_LOCALE=OCD(ID=\"{0}\") cannot support this locale \"{1}\".
34
MISSING_REQUIRED_PARAMETER=Missing required parameter: {0}
35
TOKENIZER_GOT_INVALID_DATA=The Tokenizer got invalid data.
36
INVALID_PID_METATYPE_PROVIDER_IGNORED=Bundle {0} with ID {1} provided a MetaTypeProvider with an invalid property. Property {2} with value {3} was not of the expected type (String, String[], or Collection<String>) and will be ignored.
37
METADATA_PARSE_ERROR=Unable to parse metadata XML at {0} for bundle ID {1}.
(-)src/org/eclipse/equinox/metatype/FragmentUtils.java (-58 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype;
12
13
import java.net.URL;
14
import java.util.List;
15
import org.osgi.framework.Bundle;
16
import org.osgi.framework.wiring.BundleRevision;
17
import org.osgi.framework.wiring.BundleWiring;
18
19
/*
20
 * Fragment Utilities
21
 */
22
public class FragmentUtils {
23
24
	/*
25
	 * 
26
	 */
27
	public static boolean isFragment(Bundle bundle) {
28
		return (bundle.adapt(BundleRevision.class).getTypes() & BundleRevision.TYPE_FRAGMENT) != 0;
29
	}
30
31
	/*
32
	 * Find all the URLs to entries for the bundle and its fragments.
33
	 */
34
	public static URL[] findEntries(Bundle bundle, String path) {
35
		BundleWiring wiring = bundle.adapt(BundleWiring.class);
36
		if (wiring == null)
37
			return null;
38
		String directory = "/"; //$NON-NLS-1$
39
		String file = "*"; //$NON-NLS-1$
40
		int index = path.lastIndexOf(MetaTypeProviderImpl.DIRECTORY_SEP);
41
		switch (index) {
42
			case -1 :
43
				file = path;
44
				break;
45
			case 0 :
46
				if (path.length() > 1)
47
					file = path.substring(1);
48
				break;
49
			default :
50
				directory = path.substring(0, index);
51
				file = path.substring(index + 1);
52
		}
53
		List<URL> entries = wiring.findEntries(directory, file, 0);
54
		if (entries == null)
55
			return null;
56
		return entries.toArray(new URL[entries.size()]);
57
	}
58
}
(-)src/org/eclipse/equinox/metatype/Icon.java (-72 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005 IBM Corporation.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype;
12
13
import org.osgi.framework.Bundle;
14
15
/**
16
 * Represents an Icon with a name and a size
17
 */
18
class Icon implements Cloneable {
19
20
	private String _fileName;
21
	private int _size;
22
	private Bundle _bundle;
23
24
	/**
25
	 * Constructor of class Icon.
26
	 */
27
	public Icon(String fileName, int size, Bundle bundle) {
28
29
		this._fileName = fileName;
30
		this._size = size;
31
		this._bundle = bundle;
32
	}
33
34
	/**
35
	 * Constructor of class Icon.
36
	 */
37
	public Icon(String fileName, Bundle bundle) {
38
39
		// Integer.MIN_VALUE signifies size was not specified
40
		this(fileName, Integer.MIN_VALUE, bundle);
41
	}
42
43
	/*
44
	 * 
45
	 */
46
	public synchronized Object clone() {
47
		return new Icon(this._fileName, this._size, this._bundle);
48
	}
49
50
	/**
51
	 * Method to get the icon's file name.
52
	 */
53
	String getIconName() {
54
		return _fileName;
55
	}
56
57
	/**
58
	 * returns the size specified when the icon was created
59
	 * 
60
	 * @return size or Integer.MIN_VALUE if no size was specified
61
	 */
62
	int getIconSize() {
63
		return _size;
64
	}
65
66
	/**
67
	 * Method to get the bundle having this Icon.
68
	 */
69
	Bundle getIconBundle() {
70
		return _bundle;
71
	}
72
}
(-)src/org/eclipse/equinox/metatype/LocalizationElement.java (-55 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype;
12
13
import java.util.MissingResourceException;
14
import java.util.ResourceBundle;
15
16
public class LocalizationElement {
17
18
	public static final char KEY_SIGN = '%';
19
	String _localization = null;
20
	ResourceBundle _rb;
21
22
	/**
23
	 * Internal method
24
	 */
25
	void setResourceBundle(ResourceBundle rb) {
26
		this._rb = rb;
27
	}
28
29
	/**
30
	 * Method to get the localized text of inputed String.
31
	 */
32
	String getLocalized(String key) {
33
34
		if (key == null) {
35
			return null;
36
		}
37
38
		if ((key.length() > 1) && (key.charAt(0) == KEY_SIGN)) {
39
			if (_rb != null) {
40
				try {
41
					String transfered = _rb.getString(key.substring(1));
42
					if (transfered != null) {
43
						return transfered;
44
					}
45
				} catch (MissingResourceException mre) {
46
					// Nothing found for this key.
47
				}
48
			}
49
			// If no localization file available or no localized value found
50
			// for the key, then return the raw data without the key-sign.
51
			return key.substring(1);
52
		}
53
		return key;
54
	}
55
}
(-)src/org/eclipse/equinox/metatype/LogMessages.properties (-17 lines)
Removed Link Here
1
###############################################################################
2
# Copyright (c) 2005, 2010 IBM Corporation and others.
3
# All rights reserved. This program and the accompanying materials
4
# are made available under the terms of the Eclipse Public License v1.0
5
# which accompanies this distribution, and is available at
6
# http://www.eclipse.org/legal/epl-v10.html
7
#
8
# Contributors:
9
#     IBM Corporation - initial API and implementation
10
###############################################################################
11
# NLS_MESSAGEFORMAT_ALL 
12
13
Unknown_Log_level=Unknown Log Level
14
Info=Log Info
15
Warning=Log Warning
16
Error=Log Error
17
Debug=Log Debug
(-)src/org/eclipse/equinox/metatype/LogTracker.java (-177 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 1998, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype;
12
13
import java.io.PrintStream;
14
import java.util.Calendar;
15
import java.util.Date;
16
import org.osgi.framework.BundleContext;
17
import org.osgi.framework.ServiceReference;
18
import org.osgi.service.log.LogService;
19
import org.osgi.util.tracker.ServiceTracker;
20
21
/**
22
 * LogTracker class. This class encapsulates the LogService
23
 * and handles all issues such as the service coming and going.
24
 */
25
26
public class LogTracker extends ServiceTracker<LogService, LogService> implements LogService {
27
	/** LogService interface class name */
28
	protected final static String clazz = "org.osgi.service.log.LogService"; //$NON-NLS-1$
29
30
	/** PrintStream to use if LogService is unavailable */
31
	private final PrintStream out;
32
33
	/**
34
	 * Create new LogTracker.
35
	 *
36
	 * @param context BundleContext of parent bundle.
37
	 * @param out Default PrintStream to use if LogService is unavailable.
38
	 */
39
	public LogTracker(BundleContext context, PrintStream out) {
40
		super(context, clazz, null);
41
		this.out = out;
42
	}
43
44
	/*
45
	 * ----------------------------------------------------------------------
46
	 *      LogService Interface implementation
47
	 * ----------------------------------------------------------------------
48
	 */
49
50
	public void log(int level, String message) {
51
		log(null, level, message, null);
52
	}
53
54
	public void log(int level, String message, Throwable exception) {
55
		log(null, level, message, exception);
56
	}
57
58
	// Must suppress warnings here because the log service is not
59
	@SuppressWarnings("rawtypes")
60
	public void log(ServiceReference reference, int level, String message) {
61
		log(reference, level, message, null);
62
	}
63
64
	// Must suppress warnings here because the log service is not
65
	@SuppressWarnings("rawtypes")
66
	public synchronized void log(ServiceReference reference, int level, String message, Throwable exception) {
67
		ServiceReference<LogService>[] references = getServiceReferences();
68
69
		if (references != null) {
70
			int size = references.length;
71
72
			for (int i = 0; i < size; i++) {
73
				LogService service = getService(references[i]);
74
				if (service != null) {
75
					try {
76
						service.log(reference, level, message, exception);
77
					} catch (Exception e) {
78
						// TODO: consider printing to System Error
79
					}
80
				}
81
			}
82
83
			return;
84
		}
85
86
		noLogService(level, message, exception, reference);
87
	}
88
89
	/**
90
	 * The LogService is not available so we write the message to a PrintStream.
91
	 *
92
	 * @param level Logging level
93
	 * @param message Log message.
94
	 * @param throwable Log exception or null if none.
95
	 * @param reference ServiceReference associated with message or null if none.
96
	 */
97
	protected void noLogService(int level, String message, Throwable throwable, ServiceReference<?> reference) {
98
		if (out != null) {
99
			synchronized (out) {
100
				// Bug #113286.  If no log service present and messages are being
101
				// printed to stdout, prepend message with a timestamp.
102
				String timestamp = getDate(new Date());
103
				out.print(timestamp + " "); //$NON-NLS-1$
104
105
				switch (level) {
106
					case LOG_DEBUG : {
107
						out.print(LogTrackerMsg.Debug);
108
109
						break;
110
					}
111
					case LOG_INFO : {
112
						out.print(LogTrackerMsg.Info);
113
114
						break;
115
					}
116
					case LOG_WARNING : {
117
						out.print(LogTrackerMsg.Warning);
118
119
						break;
120
					}
121
					case LOG_ERROR : {
122
						out.print(LogTrackerMsg.Error);
123
124
						break;
125
					}
126
					default : {
127
						out.print("["); //$NON-NLS-1$
128
						out.print(LogTrackerMsg.Unknown_Log_level);
129
						out.print("]: "); //$NON-NLS-1$
130
131
						break;
132
					}
133
				}
134
135
				out.println(message);
136
137
				if (reference != null) {
138
					out.println(reference);
139
				}
140
141
				if (throwable != null) {
142
					throwable.printStackTrace(out);
143
				}
144
			}
145
		}
146
	}
147
148
	// from EclipseLog to avoid using DateFormat -- see bug 149892#c10
149
	private String getDate(Date date) {
150
		Calendar c = Calendar.getInstance();
151
		c.setTime(date);
152
		StringBuffer sb = new StringBuffer();
153
		appendPaddedInt(c.get(Calendar.YEAR), 4, sb).append('-');
154
		appendPaddedInt(c.get(Calendar.MONTH) + 1, 2, sb).append('-');
155
		appendPaddedInt(c.get(Calendar.DAY_OF_MONTH), 2, sb).append(' ');
156
		appendPaddedInt(c.get(Calendar.HOUR_OF_DAY), 2, sb).append(':');
157
		appendPaddedInt(c.get(Calendar.MINUTE), 2, sb).append(':');
158
		appendPaddedInt(c.get(Calendar.SECOND), 2, sb).append('.');
159
		appendPaddedInt(c.get(Calendar.MILLISECOND), 3, sb);
160
		return sb.toString();
161
	}
162
163
	private StringBuffer appendPaddedInt(int value, int pad, StringBuffer buffer) {
164
		pad = pad - 1;
165
		if (pad == 0)
166
			return buffer.append(Integer.toString(value));
167
		int padding = (int) Math.pow(10, pad);
168
		if (value >= padding)
169
			return buffer.append(Integer.toString(value));
170
		while (padding > value && padding > 1) {
171
			buffer.append('0');
172
			padding = padding / 10;
173
		}
174
		buffer.append(value);
175
		return buffer;
176
	}
177
}
(-)src/org/eclipse/equinox/metatype/LogTrackerMsg.java (-28 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype;
12
13
import org.eclipse.osgi.util.NLS;
14
15
public class LogTrackerMsg extends NLS {
16
	private static final String BUNDLE_NAME = "org.eclipse.equinox.metatype.LogMessages"; //$NON-NLS-1$
17
18
	public static String Unknown_Log_level;
19
	public static String Info;
20
	public static String Warning;
21
	public static String Error;
22
	public static String Debug;
23
24
	static {
25
		// initialize resource bundles
26
		NLS.initializeMessages(BUNDLE_NAME, LogTrackerMsg.class);
27
	}
28
}
(-)src/org/eclipse/equinox/metatype/MetaTypeInformationImpl.java (-88 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype;
12
13
import java.util.Enumeration;
14
import java.util.Vector;
15
import javax.xml.parsers.SAXParserFactory;
16
import org.osgi.framework.Bundle;
17
import org.osgi.service.log.LogService;
18
import org.osgi.service.metatype.MetaTypeInformation;
19
20
/**
21
 * Implementation of MetaTypeProvider
22
 * <p>
23
 * Extension of MetaTypeProvider
24
 * <p>
25
 * Provides methods to:
26
 * <p> - getPids() get the Pids for a given Locale
27
 * <p> - getFactoryPids() get the Factory Pids for a given Locale
28
 * <p>
29
 */
30
public class MetaTypeInformationImpl extends MetaTypeProviderImpl implements MetaTypeInformation {
31
32
	/**
33
	 * Constructor of class MetaTypeInformationImpl.
34
	 */
35
	MetaTypeInformationImpl(Bundle bundle, SAXParserFactory parserFactory, LogService logger) {
36
		super(bundle, parserFactory, logger);
37
	}
38
39
	/*
40
	 * (non-Javadoc)
41
	 * 
42
	 * @see org.osgi.service.metatype.MetaTypeInformation#getPids()
43
	 */
44
	public String[] getPids() {
45
46
		if (_allPidOCDs.size() == 0) {
47
			return new String[0];
48
		}
49
50
		Vector<String> pids = new Vector<String>(7);
51
		Enumeration<String> e = _allPidOCDs.keys();
52
		while (e.hasMoreElements()) {
53
			pids.addElement(e.nextElement());
54
		}
55
56
		String[] retvalue = new String[pids.size()];
57
		pids.toArray(retvalue);
58
		return retvalue;
59
	}
60
61
	/*
62
	 * (non-Javadoc)
63
	 * 
64
	 * @see org.osgi.service.metatype.MetaTypeInformation#getFactoryPids()
65
	 */
66
	public String[] getFactoryPids() {
67
		if (_allFPidOCDs.size() == 0) {
68
			return new String[0];
69
		}
70
		Vector<String> fpids = new Vector<String>(7);
71
		Enumeration<String> e = _allFPidOCDs.keys();
72
		while (e.hasMoreElements()) {
73
			fpids.addElement(e.nextElement());
74
		}
75
		String[] retvalue = new String[fpids.size()];
76
		fpids.toArray(retvalue);
77
		return retvalue;
78
	}
79
80
	/*
81
	 * (non-Javadoc)
82
	 * 
83
	 * @see org.osgi.service.metatype.MetaTypeInformation#getBundle()
84
	 */
85
	public Bundle getBundle() {
86
		return this._bundle;
87
	}
88
}
(-)src/org/eclipse/equinox/metatype/MetaTypeMsg.java (-46 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype;
12
13
import org.eclipse.osgi.util.NLS;
14
15
public class MetaTypeMsg extends NLS {
16
	private static final String BUNDLE_NAME = "org.eclipse.equinox.metatype.ExternalMessages"; //$NON-NLS-1$
17
18
	public static String SERVICE_DESCRIPTION;
19
	public static String UNEXPECTED_ELEMENT;
20
	public static String UNEXPECTED_TEXT;
21
	public static String MISSING_ATTRIBUTE;
22
	public static String INVALID_TYPE;
23
	public static String MISSING_DESIGNATE_PID_AND_FACTORYPID;
24
	public static String OCD_ID_NOT_FOUND;
25
	public static String MISSING_ELEMENT;
26
	public static String EXCEPTION_MESSAGE;
27
	public static String NULL_IS_INVALID;
28
	public static String VALUE_OUT_OF_RANGE;
29
	public static String VALUE_OUT_OF_OPTION;
30
	public static String CARDINALITY_VIOLATION;
31
	public static String NULL_OPTIONS;
32
	public static String INCONSISTENT_OPTIONS;
33
	public static String INVALID_OPTIONS;
34
	public static String INVALID_DEFAULTS;
35
	public static String METADATA_NOT_FOUND;
36
	public static String ASK_INVALID_LOCALE;
37
	public static String MISSING_REQUIRED_PARAMETER;
38
	public static String TOKENIZER_GOT_INVALID_DATA;
39
	public static String INVALID_PID_METATYPE_PROVIDER_IGNORED;
40
	public static String METADATA_PARSE_ERROR;
41
42
	static {
43
		// initialize resource bundles
44
		NLS.initializeMessages(BUNDLE_NAME, MetaTypeMsg.class);
45
	}
46
}
(-)src/org/eclipse/equinox/metatype/MetaTypeProviderImpl.java (-236 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype;
12
13
import java.io.IOException;
14
import java.net.URL;
15
import java.util.*;
16
import javax.xml.parsers.SAXParserFactory;
17
import org.eclipse.osgi.util.NLS;
18
import org.osgi.framework.Bundle;
19
import org.osgi.framework.Constants;
20
import org.osgi.framework.wiring.BundleWiring;
21
import org.osgi.service.log.LogService;
22
import org.osgi.service.metatype.*;
23
24
/**
25
 * Implementation of MetaTypeProvider
26
 */
27
public class MetaTypeProviderImpl implements MetaTypeProvider {
28
29
	public static final String METADATA_NOT_FOUND = "METADATA_NOT_FOUND"; //$NON-NLS-1$
30
	public static final String OCD_ID_NOT_FOUND = "OCD_ID_NOT_FOUND"; //$NON-NLS-1$
31
	public static final String ASK_INVALID_LOCALE = "ASK_INVALID_LOCALE"; //$NON-NLS-1$
32
33
	public static final String META_FILE_EXT = ".XML"; //$NON-NLS-1$
34
	public static final String RESOURCE_FILE_CONN = "_"; //$NON-NLS-1$
35
	public static final String RESOURCE_FILE_EXT = ".properties"; //$NON-NLS-1$
36
	public static final char DIRECTORY_SEP = '/';
37
38
	Bundle _bundle;
39
40
	Hashtable<String, ObjectClassDefinitionImpl> _allPidOCDs = new Hashtable<String, ObjectClassDefinitionImpl>(7);
41
	Hashtable<String, ObjectClassDefinitionImpl> _allFPidOCDs = new Hashtable<String, ObjectClassDefinitionImpl>(7);
42
43
	String[] _locales;
44
	boolean _isThereMeta = false;
45
46
	// Give access to subclasses.
47
	protected final LogService logger;
48
49
	/**
50
	 * Constructor of class MetaTypeProviderImpl.
51
	 */
52
	MetaTypeProviderImpl(Bundle bundle, SAXParserFactory parserFactory, LogService logger) {
53
54
		this._bundle = bundle;
55
		this.logger = logger;
56
57
		// read all bundle's metadata files and build internal data structures
58
		_isThereMeta = readMetaFiles(bundle, parserFactory);
59
60
		if (!_isThereMeta) {
61
			logger.log(LogService.LOG_DEBUG, NLS.bind(MetaTypeMsg.METADATA_NOT_FOUND, new Long(bundle.getBundleId()), bundle.getSymbolicName()));
62
		}
63
	}
64
65
	/**
66
	 * This method should do the following:
67
	 * <p> - Obtain a SAX parser from the XML Parser Service:
68
	 * <p>
69
	 * 
70
	 * <pre>	</pre>
71
	 * 
72
	 * The parser may be SAX 1 (eXML) or SAX 2 (XML4J). It should attempt to use
73
	 * a SAX2 parser by instantiating an XMLReader and extending DefaultHandler
74
	 * BUT if that fails it should fall back to instantiating a SAX1 Parser and
75
	 * extending HandlerBase.
76
	 * <p> - Pass the parser the URL for the bundle's METADATA.XML file
77
	 * <p> - Handle the callbacks from the parser and build the appropriate
78
	 * MetaType objects - ObjectClassDefinitions & AttributeDefinitions
79
	 * 
80
	 * @param bundle The bundle object for which the metadata should be read
81
	 * @param parserFactory The bundle object for which the metadata should be
82
	 *        read
83
	 * @return void
84
	 * @throws IOException If there are errors accessing the metadata.xml file
85
	 */
86
	private boolean readMetaFiles(Bundle bundle, SAXParserFactory parserFactory) {
87
		BundleWiring wiring = bundle.adapt(BundleWiring.class);
88
		if (wiring == null)
89
			return false;
90
		List<URL> entries = wiring.findEntries(MetaTypeService.METATYPE_DOCUMENTS_LOCATION, "*", 0); //$NON-NLS-1$
91
		if (entries == null)
92
			return false;
93
		boolean result = false;
94
		for (URL entry : entries) {
95
			if (entry.getPath().endsWith("/"))
96
				continue;
97
			DataParser parser = new DataParser(bundle, entry, parserFactory, logger);
98
			try {
99
				Collection<Designate> designates = parser.doParse();
100
				if (!designates.isEmpty()) {
101
					result = true;
102
				}
103
				for (Designate designate : designates) {
104
					if (designate.isFactory()) {
105
						_allFPidOCDs.put(designate.getFactoryPid(), designate.getObjectClassDefinition());
106
					} else {
107
						_allPidOCDs.put(designate.getPid(), designate.getObjectClassDefinition());
108
					}
109
				}
110
			} catch (Exception e) {
111
				logger.log(LogService.LOG_ERROR, NLS.bind(MetaTypeMsg.METADATA_PARSE_ERROR, new Object[] {entry, bundle.getBundleId()}), e);
112
			}
113
		}
114
		return result;
115
	}
116
117
	/*
118
	 * (non-Javadoc)
119
	 * 
120
	 * @see org.osgi.service.metatype.MetaTypeProvider#getObjectClassDefinition(java.lang.String,
121
	 *      java.lang.String)
122
	 */
123
	public ObjectClassDefinition getObjectClassDefinition(String pid, String locale) {
124
125
		if (isInvalidLocale(locale)) {
126
			throw new IllegalArgumentException(NLS.bind(MetaTypeMsg.ASK_INVALID_LOCALE, pid, locale));
127
		}
128
129
		ObjectClassDefinitionImpl ocd;
130
		if (_allPidOCDs.containsKey(pid)) {
131
			ocd = (ObjectClassDefinitionImpl) (_allPidOCDs.get(pid)).clone();
132
			ocd.setResourceBundle(locale, _bundle);
133
			return ocd;
134
		} else if (_allFPidOCDs.containsKey(pid)) {
135
			ocd = (ObjectClassDefinitionImpl) (_allFPidOCDs.get(pid)).clone();
136
			ocd.setResourceBundle(locale, _bundle);
137
			return ocd;
138
		} else {
139
			throw new IllegalArgumentException(NLS.bind(MetaTypeMsg.OCD_ID_NOT_FOUND, pid));
140
		}
141
	}
142
143
	/**
144
	 * Internal Method - Check if the locale is invalid.
145
	 */
146
	public boolean isInvalidLocale(String locale) {
147
148
		// Just a simple and quick check here.
149
		if (locale == null || locale.length() == 0)
150
			return false;
151
152
		int idx_first = locale.indexOf(ObjectClassDefinitionImpl.LOCALE_SEP);
153
		int idx_second = locale.lastIndexOf(ObjectClassDefinitionImpl.LOCALE_SEP);
154
		if (idx_first == -1 && locale.length() == 2)
155
			// It is format of only language.
156
			return false;
157
		if ((idx_first == 2) && (idx_second == 5 || idx_second == 2))
158
			// It is format of language + "_" + country [ + "_" + variation ].
159
			return false;
160
		return true;
161
	}
162
163
	/*
164
	 * (non-Javadoc)
165
	 * 
166
	 * @see org.osgi.service.metatype.MetaTypeProvider#getLocales()
167
	 */
168
	public synchronized String[] getLocales() {
169
170
		if (_locales != null)
171
			return checkForDefault(_locales);
172
		BundleWiring wiring = _bundle.adapt(BundleWiring.class);
173
		if (wiring == null)
174
			return null;
175
		Vector<String> localizationFiles = new Vector<String>(7);
176
		// get all the localization resources for PIDS
177
		Enumeration<ObjectClassDefinitionImpl> ocds = _allPidOCDs.elements();
178
		while (ocds.hasMoreElements()) {
179
			ObjectClassDefinitionImpl ocd = ocds.nextElement();
180
			if (ocd._localization != null && !localizationFiles.contains(ocd._localization))
181
				localizationFiles.add(ocd._localization);
182
		}
183
		// get all the localization resources for FPIDS
184
		ocds = _allFPidOCDs.elements();
185
		while (ocds.hasMoreElements()) {
186
			ObjectClassDefinitionImpl ocd = ocds.nextElement();
187
			if (ocd._localization != null && !localizationFiles.contains(ocd._localization))
188
				localizationFiles.add(ocd._localization);
189
		}
190
		if (localizationFiles.size() == 0)
191
			localizationFiles.add(getBundleLocalization(_bundle));
192
		Vector<String> locales = new Vector<String>(7);
193
		Enumeration<String> eLocalizationFiles = localizationFiles.elements();
194
		while (eLocalizationFiles.hasMoreElements()) {
195
			String localizationFile = eLocalizationFiles.nextElement();
196
			int iSlash = localizationFile.lastIndexOf(DIRECTORY_SEP);
197
			String baseDir;
198
			String baseFileName;
199
			if (iSlash < 0) {
200
				baseDir = ""; //$NON-NLS-1$
201
			} else {
202
				baseDir = localizationFile.substring(0, iSlash);
203
			}
204
			baseFileName = '/' + localizationFile + RESOURCE_FILE_CONN;
205
			List<URL> entries = wiring.findEntries(baseDir, "*.properties", 0); //$NON-NLS-1$
206
			if (entries == null)
207
				continue;
208
			for (URL entry : entries) {
209
				String resource = entry.getPath();
210
				if (resource.startsWith(baseFileName) && resource.toLowerCase().endsWith(RESOURCE_FILE_EXT))
211
					locales.add(resource.substring(baseFileName.length(), resource.length() - RESOURCE_FILE_EXT.length()));
212
			}
213
		}
214
		_locales = locales.toArray(new String[locales.size()]);
215
		return checkForDefault(_locales);
216
	}
217
218
	static String getBundleLocalization(Bundle bundle) {
219
		// Use the Bundle-Localization manifest header value if it exists.
220
		String baseName = bundle.getHeaders("").get(Constants.BUNDLE_LOCALIZATION); //$NON-NLS-1$
221
		if (baseName == null)
222
			// If the manifest header does not exist, use the default.
223
			baseName = Constants.BUNDLE_LOCALIZATION_DEFAULT_BASENAME;
224
		return baseName;
225
	}
226
227
	/**
228
	 * Internal Method - checkForDefault
229
	 */
230
	private String[] checkForDefault(String[] locales) {
231
232
		if (locales == null || locales.length == 0 || (locales.length == 1 && Locale.getDefault().toString().equals(locales[0])))
233
			return null;
234
		return locales;
235
	}
236
}
(-)src/org/eclipse/equinox/metatype/MetaTypeProviderTracker.java (-189 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype;
12
13
import java.util.*;
14
import org.eclipse.osgi.util.NLS;
15
import org.osgi.framework.*;
16
import org.osgi.service.cm.ManagedService;
17
import org.osgi.service.cm.ManagedServiceFactory;
18
import org.osgi.service.log.LogService;
19
import org.osgi.service.metatype.*;
20
import org.osgi.util.tracker.ServiceTracker;
21
22
public class MetaTypeProviderTracker implements MetaTypeInformation {
23
	private final Bundle _bundle;
24
	private final LogService log;
25
	private final ServiceTracker<Object, Object> _tracker;
26
27
	/**
28
	 * Constructs a MetaTypeProviderTracker which tracks all MetaTypeProviders
29
	 * registered by the specified bundle.
30
	 * @param context The BundleContext of the MetaTypeService implementation
31
	 * @param bundle The bundle to track all MetaTypeProviders for.
32
	 * @param log The {@code LogService} to use for logging messages.
33
	 */
34
	public MetaTypeProviderTracker(Bundle bundle, LogService log, ServiceTracker<Object, Object> tracker) {
35
		this._bundle = bundle;
36
		this._tracker = tracker;
37
		this.log = log;
38
	}
39
40
	private String[] getPids(boolean factory) {
41
		if (_bundle.getState() != Bundle.ACTIVE)
42
			return new String[0]; // return none if not active
43
		MetaTypeProviderWrapper[] wrappers = getMetaTypeProviders();
44
		ArrayList<String> results = new ArrayList<String>();
45
		for (int i = 0; i < wrappers.length; i++) {
46
			// return only the correct type of pids (regular or factory)
47
			if (factory == wrappers[i].factory)
48
				results.add(wrappers[i].pid);
49
		}
50
		return results.toArray(new String[results.size()]);
51
	}
52
53
	public String[] getPids() {
54
		return getPids(false);
55
	}
56
57
	public String[] getFactoryPids() {
58
		return getPids(true);
59
	}
60
61
	public Bundle getBundle() {
62
		return _bundle;
63
	}
64
65
	public ObjectClassDefinition getObjectClassDefinition(String id, String locale) {
66
		if (_bundle.getState() != Bundle.ACTIVE)
67
			return null; // return none if not active
68
		MetaTypeProviderWrapper[] wrappers = getMetaTypeProviders();
69
		for (int i = 0; i < wrappers.length; i++) {
70
			if (id.equals(wrappers[i].pid))
71
				// found a matching pid now call the actual provider
72
				return wrappers[i].provider.getObjectClassDefinition(id, locale);
73
		}
74
		return null;
75
	}
76
77
	public String[] getLocales() {
78
		if (_bundle.getState() != Bundle.ACTIVE)
79
			return new String[0]; // return none if not active
80
		MetaTypeProviderWrapper[] wrappers = getMetaTypeProviders();
81
		ArrayList<String> locales = new ArrayList<String>();
82
		// collect all the unique locales from all providers we found
83
		for (int i = 0; i < wrappers.length; i++) {
84
			String[] wrappedLocales = wrappers[i].provider.getLocales();
85
			if (wrappedLocales == null)
86
				continue;
87
			for (int j = 0; j < wrappedLocales.length; j++)
88
				if (!locales.contains(wrappedLocales[j]))
89
					locales.add(wrappedLocales[j]);
90
		}
91
		return locales.toArray(new String[locales.size()]);
92
	}
93
94
	private MetaTypeProviderWrapper[] getMetaTypeProviders() {
95
		Map<ServiceReference<Object>, Object> services = _tracker.getTracked();
96
		if (services.isEmpty())
97
			return new MetaTypeProviderWrapper[0];
98
		Set<ServiceReference<Object>> serviceReferences = services.keySet();
99
		Set<MetaTypeProviderWrapper> result = new HashSet<MetaTypeProviderWrapper>();
100
		for (ServiceReference<Object> serviceReference : serviceReferences) {
101
			if (serviceReference.getBundle() == _bundle) {
102
				Object service = services.get(serviceReference);
103
				// If the service is not a MetaTypeProvider, we're not interested in it.
104
				if (service instanceof MetaTypeProvider) {
105
					// Include the METATYPE_PID, if present, to return as part of getPids(). Also, include the 
106
					// METATYPE_FACTORY_PID, if present, to return as part of getFactoryPids().
107
					// The filter ensures at least one of these properties was set for a standalone MetaTypeProvider.
108
					addMetaTypeProviderWrappers(MetaTypeProvider.METATYPE_PID, serviceReference, (MetaTypeProvider) service, false, result);
109
					addMetaTypeProviderWrappers(MetaTypeProvider.METATYPE_FACTORY_PID, serviceReference, (MetaTypeProvider) service, true, result);
110
					// If the service is a ManagedService, include the SERVICE_PID to return as part of getPids().
111
					// The filter ensures the SERVICE_PID property was set.
112
					if (service instanceof ManagedService) {
113
						addMetaTypeProviderWrappers(Constants.SERVICE_PID, serviceReference, (MetaTypeProvider) service, false, result);
114
					}
115
					// If the service is a ManagedServiceFactory, include the SERVICE_PID to return as part of getFactoryPids().
116
					// The filter ensures the SERVICE_PID property was set.
117
					else if (service instanceof ManagedServiceFactory) {
118
						addMetaTypeProviderWrappers(Constants.SERVICE_PID, serviceReference, (MetaTypeProvider) service, true, result);
119
					}
120
				}
121
			}
122
		}
123
		return result.toArray(new MetaTypeProviderWrapper[result.size()]);
124
	}
125
126
	private void addMetaTypeProviderWrappers(String servicePropertyName, ServiceReference<Object> serviceReference, MetaTypeProvider service, boolean factory, Set<MetaTypeProviderWrapper> wrappers) {
127
		String[] pids = getStringProperty(servicePropertyName, serviceReference.getProperty(servicePropertyName));
128
		for (String pid : pids) {
129
			wrappers.add(new MetaTypeProviderWrapper(service, pid, factory));
130
		}
131
	}
132
133
	private String[] getStringProperty(String name, Object value) {
134
		// Don't log a warning if the value is null. The filter guarantees at least one of the necessary properties
135
		// is there. If others are not, this method will get called with value equal to null.
136
		if (value == null)
137
			return new String[0];
138
		if (value instanceof String) {
139
			return new String[] {(String) value};
140
		}
141
		if (value instanceof String[]) {
142
			return (String[]) value;
143
		}
144
		Exception e = null;
145
		if (value instanceof Collection) {
146
			@SuppressWarnings("unchecked")
147
			Collection<String> temp = (Collection<String>) value;
148
			try {
149
				return temp.toArray(new String[temp.size()]);
150
			} catch (ArrayStoreException ase) {
151
				e = ase;
152
			}
153
		}
154
		log.log(LogService.LOG_WARNING, NLS.bind(MetaTypeMsg.INVALID_PID_METATYPE_PROVIDER_IGNORED, new Object[] {_bundle.getSymbolicName(), _bundle.getBundleId(), name, value}), e);
155
		return new String[0];
156
	}
157
158
	// this is a simple class just used to temporarily store information about a provider
159
	public class MetaTypeProviderWrapper {
160
		MetaTypeProvider provider;
161
		String pid;
162
		boolean factory;
163
164
		MetaTypeProviderWrapper(MetaTypeProvider provider, String pid, boolean factory) {
165
			this.provider = provider;
166
			this.pid = pid;
167
			this.factory = factory;
168
		}
169
170
		@Override
171
		public boolean equals(Object object) {
172
			if (object == this)
173
				return true;
174
			if (!(object instanceof MetaTypeProviderWrapper))
175
				return false;
176
			MetaTypeProviderWrapper that = (MetaTypeProviderWrapper) object;
177
			return this.provider.equals(that.provider) && this.pid.equals(that.pid) && this.factory == that.factory;
178
		}
179
180
		@Override
181
		public int hashCode() {
182
			int result = 17;
183
			result = 31 * result + provider.hashCode();
184
			result = 31 * result + pid.hashCode();
185
			result = 31 * result + (factory ? 1 : 0);
186
			return result;
187
		}
188
	}
189
}
(-)src/org/eclipse/equinox/metatype/MetaTypeServiceImpl.java (-107 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype;
12
13
import java.security.AccessController;
14
import java.security.PrivilegedExceptionAction;
15
import java.util.Hashtable;
16
import javax.xml.parsers.SAXParserFactory;
17
import org.eclipse.osgi.util.NLS;
18
import org.osgi.framework.*;
19
import org.osgi.service.log.LogService;
20
import org.osgi.service.metatype.MetaTypeInformation;
21
import org.osgi.service.metatype.MetaTypeService;
22
import org.osgi.util.tracker.ServiceTracker;
23
24
/**
25
 * Implementation of MetaTypeService
26
 */
27
public class MetaTypeServiceImpl implements MetaTypeService, SynchronousBundleListener {
28
29
	SAXParserFactory _parserFactory;
30
	private Hashtable<Long, MetaTypeInformation> _mtps = new Hashtable<Long, MetaTypeInformation>(7);
31
32
	private final LogService logger;
33
	private final ServiceTracker<Object, Object> metaTypeProviderTracker;
34
35
	/**
36
	 * Constructor of class MetaTypeServiceImpl.
37
	 */
38
	public MetaTypeServiceImpl(SAXParserFactory parserFactory, LogService logger, ServiceTracker<Object, Object> metaTypeProviderTracker) {
39
		this._parserFactory = parserFactory;
40
		this.logger = logger;
41
		this.metaTypeProviderTracker = metaTypeProviderTracker;
42
	}
43
44
	/*
45
	 * (non-Javadoc)
46
	 * 
47
	 * @see org.osgi.service.metatype.MetaTypeService#getMetaTypeInformation(org.osgi.framework.Bundle)
48
	 */
49
	public MetaTypeInformation getMetaTypeInformation(Bundle bundle) {
50
		return getMetaTypeProvider(bundle);
51
	}
52
53
	/**
54
	 * Internal Method - to get MetaTypeProvider object.
55
	 */
56
	private MetaTypeInformation getMetaTypeProvider(final Bundle b) {
57
		final LogService loggerTemp = this.logger;
58
		final ServiceTracker<Object, Object> tracker = this.metaTypeProviderTracker;
59
		try {
60
			Long bID = new Long(b.getBundleId());
61
			synchronized (_mtps) {
62
				if (_mtps.containsKey(bID))
63
					return _mtps.get(bID);
64
				// Avoid synthetic accessor method warnings.
65
66
				MetaTypeInformation mti = AccessController.doPrivileged(new PrivilegedExceptionAction<MetaTypeInformation>() {
67
					public MetaTypeInformation run() {
68
						MetaTypeInformationImpl impl = new MetaTypeInformationImpl(b, _parserFactory, loggerTemp);
69
						if (!impl._isThereMeta)
70
							return new MetaTypeProviderTracker(b, loggerTemp, tracker);
71
						return impl;
72
					}
73
				});
74
				_mtps.put(bID, mti);
75
				return mti;
76
			}
77
		} catch (Exception e) {
78
			logger.log(LogService.LOG_ERROR, NLS.bind(MetaTypeMsg.EXCEPTION_MESSAGE, e.getMessage()), e);
79
			return new MetaTypeProviderTracker(b, loggerTemp, tracker);
80
		}
81
	}
82
83
	/*
84
	 * (non-Javadoc)
85
	 * 
86
	 * @see org.osgi.framework.BundleListener#bundleChanged(org.osgi.framework.BundleEvent)
87
	 */
88
	public void bundleChanged(BundleEvent event) {
89
90
		int type = event.getType();
91
		Long bID = new Long(event.getBundle().getBundleId());
92
93
		switch (type) {
94
			case BundleEvent.UPDATED :
95
			case BundleEvent.UNINSTALLED :
96
				_mtps.remove(bID);
97
				break;
98
			case BundleEvent.INSTALLED :
99
			case BundleEvent.RESOLVED :
100
			case BundleEvent.STARTED :
101
			case BundleEvent.STOPPED :
102
			case BundleEvent.UNRESOLVED :
103
			default :
104
				break;
105
		}
106
	}
107
}
(-)src/org/eclipse/equinox/metatype/ObjectClassDefinitionImpl.java (-313 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype;
12
13
import java.io.IOException;
14
import java.io.InputStream;
15
import java.net.URL;
16
import java.util.*;
17
import org.osgi.framework.Bundle;
18
import org.osgi.service.metatype.AttributeDefinition;
19
import org.osgi.service.metatype.ObjectClassDefinition;
20
21
/**
22
 * Implementation of ObjectClassDefinition
23
 */
24
public class ObjectClassDefinitionImpl extends LocalizationElement implements ObjectClassDefinition, Cloneable {
25
26
	public static final char LOCALE_SEP = '_';
27
28
	String _name;
29
	String _id;
30
	String _description;
31
32
	int _type;
33
	Vector<AttributeDefinitionImpl> _required = new Vector<AttributeDefinitionImpl>(7);
34
	Vector<AttributeDefinitionImpl> _optional = new Vector<AttributeDefinitionImpl>(7);
35
	Icon _icon;
36
37
	/*
38
	 * Constructor of class ObjectClassDefinitionImpl.
39
	 */
40
	public ObjectClassDefinitionImpl(String name, String description, String id, String localization) {
41
42
		this._name = name;
43
		this._description = description;
44
		this._id = id;
45
		this._localization = localization;
46
	}
47
48
	/*
49
	 * Constructor of class ObjectClassDefinitionImpl.
50
	 */
51
	public ObjectClassDefinitionImpl(String name, String description, String id, int type, String localization) {
52
53
		this._name = name;
54
		this._id = id;
55
		this._description = description;
56
		this._type = type;
57
		this._localization = localization;
58
	}
59
60
	/*
61
	 * 
62
	 */
63
	public synchronized Object clone() {
64
65
		ObjectClassDefinitionImpl ocd = new ObjectClassDefinitionImpl(_name, _description, _id, _type, _localization);
66
		for (int i = 0; i < _required.size(); i++) {
67
			AttributeDefinitionImpl ad = _required.elementAt(i);
68
			ocd.addAttributeDefinition((AttributeDefinitionImpl) ad.clone(), true);
69
		}
70
		for (int i = 0; i < _optional.size(); i++) {
71
			AttributeDefinitionImpl ad = _optional.elementAt(i);
72
			ocd.addAttributeDefinition((AttributeDefinitionImpl) ad.clone(), false);
73
		}
74
		if (_icon != null) {
75
			ocd.setIcon((Icon) _icon.clone());
76
		}
77
		return ocd;
78
	}
79
80
	/*
81
	 * (non-Javadoc)
82
	 * 
83
	 * @see org.osgi.service.metatype.ObjectClassDefinition#getName()
84
	 */
85
	public String getName() {
86
		return getLocalized(_name);
87
	}
88
89
	/**
90
	 * Method to set the name of ObjectClassDefinition.
91
	 */
92
	void setName(String name) {
93
		this._name = name;
94
	}
95
96
	/*
97
	 * (non-Javadoc)
98
	 * 
99
	 * @see org.osgi.service.metatype.ObjectClassDefinition#getID()
100
	 */
101
	public String getID() {
102
		return _id;
103
	}
104
105
	/*
106
	 * (non-Javadoc)
107
	 * 
108
	 * @see org.osgi.service.metatype.ObjectClassDefinition#getDescription()
109
	 */
110
	public String getDescription() {
111
		return getLocalized(_description);
112
	}
113
114
	/*
115
	 * Method to set the description of ObjectClassDefinition.
116
	 */
117
	void setDescription(String description) {
118
		this._description = description;
119
	}
120
121
	/*
122
	 * (non-Javadoc)
123
	 * 
124
	 * @see org.osgi.service.metatype.ObjectClassDefinition#getAttributeDefinitions(int)
125
	 */
126
	public AttributeDefinition[] getAttributeDefinitions(int filter) {
127
128
		AttributeDefinition[] atts;
129
		switch (filter) {
130
			case REQUIRED :
131
				atts = new AttributeDefinition[_required.size()];
132
				_required.toArray(atts);
133
				return atts;
134
			case OPTIONAL :
135
				atts = new AttributeDefinition[_optional.size()];
136
				_optional.toArray(atts);
137
				return atts;
138
			case ALL :
139
			default :
140
				atts = new AttributeDefinition[_required.size() + _optional.size()];
141
				Enumeration<AttributeDefinitionImpl> e = _required.elements();
142
				int i = 0;
143
				while (e.hasMoreElements()) {
144
					atts[i] = e.nextElement();
145
					i++;
146
				}
147
				e = _optional.elements();
148
				while (e.hasMoreElements()) {
149
					atts[i] = e.nextElement();
150
					i++;
151
				}
152
				return atts;
153
		}
154
	}
155
156
	/*
157
	 * Method to add one new AD to ObjectClassDefinition.
158
	 */
159
	void addAttributeDefinition(AttributeDefinitionImpl ad, boolean isRequired) {
160
161
		if (isRequired) {
162
			_required.addElement(ad);
163
		} else {
164
			_optional.addElement(ad);
165
		}
166
	}
167
168
	/*
169
	 * (non-Javadoc)
170
	 * 
171
	 * @see org.osgi.service.metatype.ObjectClassDefinition#getIcon(int)
172
	 */
173
	public InputStream getIcon(int sizeHint) throws IOException {
174
		// The parameter simply represents a requested size. This method should never return null if an
175
		// icon exists.
176
		// TODO This method may change further depending on the outcome of certain ongoing CPEG discussions.
177
		// It is thought that users should be able to specify the same icon multiple times but of different
178
		// sizes. This would require a change to the XML schema. This method would then return the icon with
179
		// a size closest to the requested size.
180
		if ((_icon == null)) {
181
			return null;
182
		}
183
		Bundle b = _icon.getIconBundle();
184
		URL[] urls = FragmentUtils.findEntries(b, getLocalized(_icon.getIconName()));
185
		if (urls != null && urls.length > 0) {
186
			return urls[0].openStream();
187
		}
188
		return null;
189
	}
190
191
	/**
192
	 * Method to set the icon of ObjectClassDefinition.
193
	 */
194
	void setIcon(Icon icon) {
195
		this._icon = icon;
196
	}
197
198
	/**
199
	 * Method to set the resource bundle for this OCD and all its ADs.
200
	 */
201
	void setResourceBundle(String assignedLocale, Bundle bundle) {
202
203
		_rb = getResourceBundle(assignedLocale, bundle);
204
205
		Enumeration<AttributeDefinitionImpl> allADReqs = _required.elements();
206
		while (allADReqs.hasMoreElements()) {
207
			AttributeDefinitionImpl ad = allADReqs.nextElement();
208
			ad.setResourceBundle(_rb);
209
		}
210
211
		Enumeration<AttributeDefinitionImpl> allADOpts = _optional.elements();
212
		while (allADOpts.hasMoreElements()) {
213
			AttributeDefinitionImpl ad = allADOpts.nextElement();
214
			ad.setResourceBundle(_rb);
215
		}
216
	}
217
218
	/*
219
	 * Internal Method - to get resource bundle.
220
	 */
221
	private ResourceBundle getResourceBundle(String locale, final Bundle bundle) {
222
		// Determine the base name of the bundle localization property files.
223
		// If the <MetaData> 'localization' attribute was not specified,
224
		// use the Bundle-Localization manifest header value instead if it exists.
225
		String resourceBase = _localization != null ? _localization : MetaTypeProviderImpl.getBundleLocalization(bundle);
226
227
		// There are seven searching candidates possible:
228
		// baseName + 
229
		//		"_" + language1 + "_" + country1 + "_" + variation1	+ ".properties"
230
		// or	"_" + language1 + "_" + country1					+ ".properties"
231
		// or	"_" + language1										+ ".properties"
232
		// or	"_" + language2 + "_" + country2 + "_" + variation2	+ ".properties"
233
		// or	"_" + language2 + "_" + country2					+ ".properties"
234
		// or	"_" + language2										+ ".properties"
235
		// or	""													+ ".properties"
236
		//
237
		// Where language1[_country1[_variation1]] is the requested locale,
238
		// and language2[_country2[_variation2]] is the default locale.
239
240
		String[] searchCandidates = new String[7];
241
242
		// Candidates from passed locale:
243
		if (locale != null && locale.length() > 0) {
244
			int idx1_first = locale.indexOf(LOCALE_SEP);
245
			if (idx1_first == -1) {
246
				// locale has only language.
247
				searchCandidates[2] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + locale;
248
			} else {
249
				// locale has at least language and country.
250
				searchCandidates[2] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + locale.substring(0, idx1_first);
251
				int idx1_second = locale.indexOf(LOCALE_SEP, idx1_first + 1);
252
				if (idx1_second == -1) {
253
					// locale just has both language and country.
254
					searchCandidates[1] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + locale;
255
				} else {
256
					// locale has language, country, and variation all.
257
					searchCandidates[1] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + locale.substring(0, idx1_second);
258
					searchCandidates[0] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + locale;
259
				}
260
			}
261
		}
262
263
		// Candidates from Locale.getDefault():
264
		String defaultLocale = Locale.getDefault().toString();
265
		int idx2_first = defaultLocale.indexOf(LOCALE_SEP);
266
		int idx2_second = defaultLocale.indexOf(LOCALE_SEP, idx2_first + 1);
267
		if (idx2_second != -1) {
268
			// default-locale is format of [language]_[country]_variation.
269
			searchCandidates[3] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + defaultLocale;
270
			if (searchCandidates[3].equalsIgnoreCase(searchCandidates[0])) {
271
				searchCandidates[3] = null;
272
			}
273
		}
274
		if ((idx2_first != -1) && (idx2_second != idx2_first + 1)) {
275
			// default-locale is format of [language]_country[_variation].
276
			searchCandidates[4] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + ((idx2_second == -1) ? defaultLocale : defaultLocale.substring(0, idx2_second));
277
			if (searchCandidates[4].equalsIgnoreCase(searchCandidates[1])) {
278
				searchCandidates[4] = null;
279
			}
280
		}
281
		if ((idx2_first == -1) && (defaultLocale.length() > 0)) {
282
			// default-locale has only language.
283
			searchCandidates[5] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + defaultLocale;
284
		} else if (idx2_first > 0) {
285
			// default-locale is format of language_[...].
286
			searchCandidates[5] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + defaultLocale.substring(0, idx2_first);
287
		}
288
		if (searchCandidates[5] != null && searchCandidates[5].equalsIgnoreCase(searchCandidates[2])) {
289
			searchCandidates[5] = null;
290
		}
291
292
		// The final candidate.
293
		searchCandidates[6] = ""; //$NON-NLS-1$
294
295
		URL resourceUrl = null;
296
		URL[] urls = null;
297
298
		for (int idx = 0; (idx < searchCandidates.length) && (resourceUrl == null); idx++) {
299
			urls = (searchCandidates[idx] == null ? null : FragmentUtils.findEntries(bundle, resourceBase + searchCandidates[idx] + MetaTypeProviderImpl.RESOURCE_FILE_EXT));
300
			if (urls != null && urls.length > 0)
301
				resourceUrl = urls[0];
302
		}
303
304
		if (resourceUrl != null) {
305
			try {
306
				return new PropertyResourceBundle(resourceUrl.openStream());
307
			} catch (IOException ioe) {
308
				// Exception when creating PropertyResourceBundle object.
309
			}
310
		}
311
		return null;
312
	}
313
}
(-)src/org/eclipse/equinox/metatype/ValueTokenizer.java (-274 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype;
12
13
import java.math.BigDecimal;
14
import java.math.BigInteger;
15
import java.util.*;
16
import org.eclipse.osgi.util.NLS;
17
import org.osgi.service.log.LogService;
18
import org.osgi.service.metatype.AttributeDefinition;
19
20
public class ValueTokenizer {
21
	private static final char DELIMITER = ',';
22
	private static final char ESCAPE = '\\';
23
24
	private final LogService logger;
25
	private final List<String> values = new ArrayList<String>();
26
27
	/*
28
	 * Constructor of class ValueTokenizer
29
	 */
30
	public ValueTokenizer(String values_str, LogService logger) {
31
		this.logger = logger;
32
		if (values_str == null)
33
			return;
34
		// The trick is to strip out unescaped whitespace characters before and
35
		// after the input string as well as before and after each 
36
		// individual token within the input string without losing any escaped 
37
		// whitespace characters. Whitespace between two non-whitespace
38
		// characters may or may not be escaped. Also, any character may be
39
		// escaped. The escape character is '\'. The delimiter is ','.
40
		StringBuffer buffer = new StringBuffer();
41
		// Loop over the characters within the input string and extract each
42
		// value token.
43
		for (int i = 0; i < values_str.length(); i++) {
44
			char c1 = values_str.charAt(i);
45
			switch (c1) {
46
				case DELIMITER :
47
					// When the delimiter is encountered, add the extracted 
48
					// token to the result and prepare the buffer to receive the
49
					// next token.
50
					values.add(buffer.toString());
51
					buffer.delete(0, buffer.length());
52
					break;
53
				case ESCAPE :
54
					// When the escape is encountered, add the immediately
55
					// following character to the token, unless the end of the
56
					// input has been reached. Note this will result in loop 
57
					// counter 'i' being incremented twice, once here and once 
58
					// at the end of the loop.
59
					if (i + 1 < values_str.length()) {
60
						buffer.append(values_str.charAt(++i));
61
					} else {
62
						// If the ESCAPE character occurs as the last character
63
						// of the string, log the error and ignore it.
64
						logger.log(LogService.LOG_ERROR, "ValueTokenizer.ValueTokenizer(String) " + MetaTypeMsg.TOKENIZER_GOT_INVALID_DATA); //$NON-NLS-1$
65
					}
66
					break;
67
				default :
68
					// For all other characters, add them to the current token
69
					// unless dealing with unescaped whitespace at the beginning
70
					// or end. We know the whitespace is unescaped because it
71
					// would have been handled in the ESCAPE case otherwise.
72
					if (Character.isWhitespace(c1)) {
73
						// Ignore unescaped whitespace at the beginning of the
74
						// token.
75
						if (buffer.length() == 0) {
76
							continue;
77
						}
78
						// If the whitespace is not at the beginning, look
79
						// forward, starting with the next character, to see if 
80
						// it's in the middle or at the end. Unescaped 
81
						// whitespace in the middle is okay.
82
						for (int j = i + 1; j < values_str.length(); j++) {
83
							// Keep looping until the end of the string is
84
							// reached or a non-whitespace character other than
85
							// the escape is seen.
86
							char c2 = values_str.charAt(j);
87
							if (!Character.isWhitespace(c2)) {
88
								// If the current character is not the DELIMITER, all whitespace 
89
								// characters are significant and should be added to the token.
90
								// Otherwise, they're at the end and should be ignored. But watch
91
								// out for an escape character at the end of the input. Ignore it
92
								// and any previous insignificant whitespace if it exists.
93
								if (c2 == ESCAPE && j + 1 >= values_str.length()) {
94
									continue;
95
								}
96
								if (c2 != DELIMITER) {
97
									buffer.append(values_str.substring(i, j));
98
								}
99
								// Let loop counter i catch up with the inner loop but keep in
100
								// mind it will still be incremented at the end of the outer loop.
101
								i = j - 1;
102
								break;
103
							}
104
						}
105
					} else {
106
						// For non-whitespace characters.
107
						buffer.append(c1);
108
					}
109
			}
110
		}
111
		// Don't forget to add the last token.
112
		values.add(buffer.toString());
113
	}
114
115
	/*
116
	 * Method to return values as Vector.
117
	 */
118
	public Collection<String> getValues() {
119
		return Collections.unmodifiableList(values);
120
	}
121
122
	/*
123
	 * Method to return values as String[] or null.
124
	 */
125
	public String[] getValuesAsArray() {
126
		if (values.isEmpty()) {
127
			return null;
128
		}
129
		return values.toArray(new String[values.size()]);
130
	}
131
132
	public String getValuesAsString() {
133
		if (values.isEmpty()) {
134
			return null;
135
		}
136
		if (values.size() == 1) {
137
			return values.get(0);
138
		}
139
		StringBuffer buffer = new StringBuffer(values.get(0));
140
		for (int i = 1; i < values.size(); i++) {
141
			buffer.append(',');
142
			buffer.append(values.get(i));
143
		}
144
		return buffer.toString();
145
	}
146
147
	public String validate(AttributeDefinitionImpl ad) {
148
		// An empty list means the original value was null. Null is never valid.
149
		if (values.isEmpty()) {
150
			return MetaTypeMsg.NULL_IS_INVALID;
151
		}
152
		try {
153
			// A value must match the cardinality.
154
			int cardinality = Math.abs(ad.getCardinality());
155
			// If the cardinality is zero, the value must contain one and only one token.
156
			if (cardinality == 0) {
157
				if (values.size() != 1) {
158
					return NLS.bind(MetaTypeMsg.CARDINALITY_VIOLATION, new Object[] {getValuesAsString(), values.size(), 1, 1});
159
				}
160
			}
161
			// Otherwise, the number of tokens must be between 0 and cardinality, inclusive.
162
			else if (values.size() > cardinality) {
163
				return NLS.bind(MetaTypeMsg.CARDINALITY_VIOLATION, new Object[] {getValuesAsString(), values.size(), 0, cardinality});
164
			}
165
			// Now inspect each token.
166
			for (Iterator<String> i = values.iterator(); i.hasNext();) {
167
				String s = i.next();
168
				// If options were declared and the value does not match one of them, the value is not valid.
169
				if (!ad._values.isEmpty() && !ad._values.contains(s)) {
170
					return NLS.bind(MetaTypeMsg.VALUE_OUT_OF_OPTION, s);
171
				}
172
				// Check the type. Also check the range if min or max were declared.
173
				boolean rangeError = false;
174
				switch (ad._dataType) {
175
					case AttributeDefinition.PASSWORD :
176
					case AttributeDefinition.STRING :
177
						if (ad._minValue != null && s.length() < (Integer) ad._minValue) {
178
							rangeError = true;
179
						} else if (ad._maxValue != null && s.length() > (Integer) ad._maxValue) {
180
							rangeError = true;
181
						}
182
						break;
183
					case AttributeDefinition.INTEGER :
184
						Integer intVal = new Integer(s);
185
						if (ad._minValue != null && intVal.compareTo((Integer) ad._minValue) < 0) {
186
							rangeError = true;
187
						} else if (ad._maxValue != null && intVal.compareTo((Integer) ad._maxValue) > 0) {
188
							rangeError = true;
189
						}
190
						break;
191
					case AttributeDefinition.LONG :
192
						Long longVal = new Long(s);
193
						if (ad._minValue != null && longVal.compareTo((Long) ad._minValue) < 0) {
194
							rangeError = true;
195
						} else if (ad._maxValue != null && longVal.compareTo((Long) ad._maxValue) > 0) {
196
							rangeError = true;
197
						}
198
						break;
199
					case AttributeDefinition.DOUBLE :
200
						Double doubleVal = new Double(s);
201
						if (ad._minValue != null && doubleVal.compareTo((Double) ad._minValue) < 0) {
202
							rangeError = true;
203
						} else if (ad._maxValue != null && doubleVal.compareTo((Double) ad._maxValue) > 0) {
204
							rangeError = true;
205
						}
206
						break;
207
					case AttributeDefinition.BOOLEAN :
208
						// Any string can be converted into a boolean via Boolean.valueOf(String).
209
						// Seems unnecessary to impose any further restrictions.
210
						break;
211
					case AttributeDefinition.CHARACTER :
212
						Character charVal = new Character(s.charAt(0));
213
						if (ad._minValue != null && charVal.compareTo((Character) ad._minValue) < 0) {
214
							rangeError = true;
215
						} else if (ad._maxValue != null && charVal.compareTo((Character) ad._maxValue) > 0) {
216
							rangeError = true;
217
						}
218
						break;
219
					case AttributeDefinition.FLOAT :
220
						Float floatVal = new Float(s);
221
						if (ad._minValue != null && floatVal.compareTo((Float) ad._minValue) < 0) {
222
							rangeError = true;
223
						} else if (ad._maxValue != null && floatVal.compareTo((Float) ad._maxValue) > 0) {
224
							rangeError = true;
225
						}
226
						break;
227
					case AttributeDefinition.SHORT :
228
						Short shortVal = new Short(s);
229
						if (ad._minValue != null && shortVal.compareTo((Short) ad._minValue) < 0) {
230
							rangeError = true;
231
						} else if (ad._maxValue != null && shortVal.compareTo((Short) ad._maxValue) > 0) {
232
							rangeError = true;
233
						}
234
						break;
235
					case AttributeDefinition.BYTE :
236
						Byte byteVal = new Byte(s);
237
						if (ad._minValue != null && byteVal.compareTo((Byte) ad._minValue) < 0) {
238
							rangeError = true;
239
						} else if (ad._maxValue != null && byteVal.compareTo((Byte) ad._maxValue) > 0) {
240
							rangeError = true;
241
						}
242
						break;
243
					case AttributeDefinition.BIGDECIMAL :
244
						BigDecimal bigDecVal = new BigDecimal(s);
245
						if (ad._minValue != null && bigDecVal.compareTo((BigDecimal) ad._minValue) < 0) {
246
							rangeError = true;
247
						} else if (ad._maxValue != null && bigDecVal.compareTo((BigDecimal) ad._maxValue) > 0) {
248
							rangeError = true;
249
						}
250
						break;
251
					case AttributeDefinition.BIGINTEGER :
252
						BigInteger bigIntVal = new BigInteger(s);
253
						if (ad._minValue != null && bigIntVal.compareTo((BigInteger) ad._minValue) < 0) {
254
							rangeError = true;
255
						} else if (ad._maxValue != null && bigIntVal.compareTo((BigInteger) ad._maxValue) > 0) {
256
							rangeError = true;
257
						}
258
						break;
259
					default :
260
						throw new IllegalStateException();
261
				}
262
				if (rangeError) {
263
					return (NLS.bind(MetaTypeMsg.VALUE_OUT_OF_RANGE, s));
264
				}
265
			}
266
			// No problems detected
267
			return ""; //$NON-NLS-1$
268
		} catch (Throwable t) {
269
			String message = NLS.bind(MetaTypeMsg.EXCEPTION_MESSAGE, t.getClass().getName(), t.getMessage());
270
			logger.log(LogService.LOG_DEBUG, message, t);
271
			return message;
272
		}
273
	}
274
}
(-)src/org/eclipse/equinox/metatype/impl/Activator.java (+255 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype.impl;
12
13
import org.eclipse.equinox.metatype.EquinoxMetaTypeService;
14
15
import java.util.Dictionary;
16
import java.util.Hashtable;
17
import javax.xml.parsers.SAXParserFactory;
18
import org.osgi.framework.*;
19
import org.osgi.service.cm.ManagedService;
20
import org.osgi.service.log.LogService;
21
import org.osgi.service.metatype.MetaTypeProvider;
22
import org.osgi.service.metatype.MetaTypeService;
23
import org.osgi.util.tracker.ServiceTracker;
24
import org.osgi.util.tracker.ServiceTrackerCustomizer;
25
26
/**
27
 * MetaType Activator
28
 */
29
public class Activator implements BundleActivator {
30
	/*
31
	 * The following filter guarantees only services meeting the following
32
	 * criteria will be tracked.
33
	 * 
34
	 * (1) A ManagedService or ManagedServiceFactory registered with a
35
	 * SERVICE_PID property. May also be registered as a MetaTypeProvider.
36
	 * (2) A MetaTypeProvider registered with a METATYPE_PID or
37
	 * METATYPE_FACTORY_PID property.
38
	 * 
39
	 * Note that it's still necessary to inspect a ManagedService or
40
	 * ManagedServiceFactory to ensure it also implements MetaTypeProvider.
41
	 */
42
	private static final String FILTER = "(|(&(" + Constants.OBJECTCLASS + '=' + ManagedService.class.getName() + "*)(" + Constants.SERVICE_PID + "=*))(&(" + Constants.OBJECTCLASS + '=' + MetaTypeProvider.class.getName() + ")(|(" + MetaTypeProvider.METATYPE_PID + "=*)(" + MetaTypeProvider.METATYPE_FACTORY_PID + "=*))))"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
43
	private static final String SERVICE_PID = "org.osgi.impl.service.metatype.MetaTypeService"; //$NON-NLS-1$
44
45
	private LogTracker logServiceTracker;
46
	// Could be ManagedService, ManagedServiceFactory, or MetaTypeProvider.
47
	// The tracker tracks all services regardless of bundle. Services are
48
	// filtered by bundle later in the MetaTypeProviderTracker class. It may 
49
	// therefore be shared among multiple instances of that class.
50
	private ServiceTracker<Object, Object> metaTypeProviderTracker;
51
	private ServiceTracker<SAXParserFactory, SAXParserFactory> saxParserFactoryTracker;
52
53
	public void start(BundleContext context) throws InvalidSyntaxException {
54
		LogTracker lsTracker;
55
		ServiceTracker<Object, Object> mtpTracker;
56
		ServiceTracker<SAXParserFactory, SAXParserFactory> spfTracker;
57
		Filter filter = context.createFilter(FILTER);
58
		synchronized (this) {
59
			lsTracker = logServiceTracker = new LogTracker(context, System.out);
60
			mtpTracker = metaTypeProviderTracker = new ServiceTracker<Object, Object>(context, filter, null);
61
			spfTracker = saxParserFactoryTracker = new ServiceTracker<SAXParserFactory, SAXParserFactory>(context, SAXParserFactory.class, new SAXParserFactoryTrackerCustomizer(context, lsTracker, mtpTracker));
62
		}
63
		// Do this first to make logging available as early as possible.
64
		lsTracker.open();
65
		lsTracker.log(LogService.LOG_DEBUG, "====== Meta Type Service starting ! ====="); //$NON-NLS-1$
66
		// Do this next to make MetaTypeProviders available as early as possible.
67
		mtpTracker.open();
68
		// Do this last because it may result in the MetaTypeService being registered.
69
		spfTracker.open();
70
	}
71
72
	public void stop(BundleContext context) {
73
		ServiceTracker<SAXParserFactory, SAXParserFactory> spfTracker;
74
		ServiceTracker<Object, Object> mtpTracker;
75
		LogTracker lsTracker;
76
		synchronized (this) {
77
			spfTracker = saxParserFactoryTracker;
78
			// Set this to null so the SAXParserFactoryTrackerCustomizer knows
79
			// not to register a new MetaTypeService when removedService() is
80
			// called while the tracker is closing.
81
			saxParserFactoryTracker = null;
82
			mtpTracker = metaTypeProviderTracker;
83
			lsTracker = logServiceTracker;
84
		}
85
		lsTracker.log(LogService.LOG_DEBUG, "====== Meta Type Service stopping ! ====="); //$NON-NLS-1$
86
		spfTracker.close();
87
		mtpTracker.close();
88
		// Do this last to leave logging available as long as possible.
89
		lsTracker.close();
90
	}
91
92
	synchronized ServiceTracker<SAXParserFactory, SAXParserFactory> getSAXParserFactoryTracker() {
93
		return saxParserFactoryTracker;
94
	}
95
96
	private class SAXParserFactoryTrackerCustomizer implements ServiceTrackerCustomizer<SAXParserFactory, SAXParserFactory> {
97
		private final BundleContext bundleCtx;
98
		private final LogService logService;
99
		private final ServiceTracker<Object, Object> mtpTracker;
100
101
		private MetaTypeServiceImpl metaTypeService;
102
		private ServiceRegistration<?> metaTypeServiceRegistration;
103
		private SAXParserFactory saxParserFactory;
104
105
		public SAXParserFactoryTrackerCustomizer(BundleContext bundleContext, LogService logService, ServiceTracker<Object, Object> metaTypeProviderTracker) {
106
			this.bundleCtx = bundleContext;
107
			this.logService = logService;
108
			this.mtpTracker = metaTypeProviderTracker;
109
		}
110
111
		public SAXParserFactory addingService(ServiceReference<SAXParserFactory> ref) {
112
			SAXParserFactory parserFactory = bundleCtx.getService(ref);
113
			if (parserFactory == null)
114
				return null;
115
			ServiceRegistration<?> registration = null;
116
			MetaTypeServiceImpl service = null;
117
			SAXParserFactory oldFactory = null;
118
			synchronized (this) {
119
				// No previous factory case. We'll accept anything.
120
				if (saxParserFactory == null) {
121
					// Save this parserFactory as the currently used parserFactory
122
					saxParserFactory = parserFactory;
123
				}
124
				// Nothing to do case. Current factory is explicitly namespace aware.
125
				else if (saxParserFactory.isNamespaceAware()) {
126
					return parserFactory;
127
				} else if (parserFactory.isNamespaceAware() || // Previous factory not set for namespace awareness but the new one is case.
128
						// Now the fun case. Neither factory is set for namespace awareness. Need to see if we're currently using 
129
						// a factory incapable of creating namespace aware parsers and, if so, if it can be replaced with the new one.
130
						(!supportsNamespaceAwareness(saxParserFactory) && supportsNamespaceAwareness(parserFactory))) {
131
					oldFactory = saxParserFactory;
132
					saxParserFactory = parserFactory;
133
					registration = metaTypeServiceRegistration;
134
					service = metaTypeService;
135
				}
136
			}
137
			swapFactories(oldFactory, parserFactory, registration, service);
138
			return parserFactory;
139
		}
140
141
		private void swapFactories(SAXParserFactory oldFactory, SAXParserFactory newFactory, ServiceRegistration<?> registration, MetaTypeServiceImpl service) {
142
			if (oldFactory == null) {
143
				registerMetaTypeService();
144
				return;
145
			}
146
			unregisterMetaTypeService(registration, service);
147
			registerMetaTypeService();
148
		}
149
150
		public void modifiedService(ServiceReference<SAXParserFactory> ref, SAXParserFactory object) {
151
			// Nothing.
152
		}
153
154
		public void removedService(ServiceReference<SAXParserFactory> ref, SAXParserFactory object) {
155
			ServiceRegistration<?> registration = null;
156
			MetaTypeServiceImpl service = null;
157
			synchronized (this) {
158
				if (object == saxParserFactory) {
159
					// This means the SAXParserFactory was used to start the MetaTypeService and we need to reset.
160
					saxParserFactory = null;
161
					registration = metaTypeServiceRegistration;
162
					service = metaTypeService;
163
				}
164
			}
165
			if (registration != null) {
166
				// Unregister the MetaType service.
167
				unregisterMetaTypeService(registration, service);
168
				// See if another factory is available
169
				SAXParserFactory factory = findBestPossibleFactory();
170
				// If the factory is null, either the bundle is stopping or there are no
171
				// available services. Either way, we don't want to register the MetaType service.
172
				if (factory != null) {
173
					// We have another parser so let's restart the MetaType service if it hasn't been already.
174
					boolean register = false;
175
					synchronized (this) {
176
						// If not null, something else beat us to the punch.
177
						if (saxParserFactory == null) {
178
							saxParserFactory = factory;
179
							register = true;
180
						}
181
					}
182
					if (register) {
183
						registerMetaTypeService();
184
					}
185
				}
186
			}
187
			bundleCtx.ungetService(ref);
188
		}
189
190
		private SAXParserFactory findBestPossibleFactory() {
191
			ServiceTracker<SAXParserFactory, SAXParserFactory> tracker = getSAXParserFactoryTracker();
192
			// The tracker will be null if the bundle is stopping.
193
			if (tracker == null)
194
				return null;
195
			SAXParserFactory[] factories = (SAXParserFactory[]) tracker.getServices();
196
			// The factories will be null if there are no services being tracked.
197
			if (factories == null)
198
				return null;
199
			SAXParserFactory result = null;
200
			for (SAXParserFactory factory : factories) {
201
				if (factory.isNamespaceAware()) {
202
					// If the factory is namespace aware, we have exactly what we want.
203
					result = factory;
204
					break;
205
				}
206
				// If no "second best" parser has been found yet, see if this one fits the bill.
207
				if (result == null && supportsNamespaceAwareness(factory)) {
208
					result = factory;
209
				}
210
			}
211
			// If no factories capable of providing namespace aware parsers have been found,
212
			// just grab the first available one, if any.
213
			if (result == null)
214
				result = tracker.getService();
215
			return result;
216
		}
217
218
		private void registerMetaTypeService() {
219
			Dictionary<String, Object> properties = new Hashtable<String, Object>(7);
220
			properties = new Hashtable<String, Object>(7);
221
			properties.put(Constants.SERVICE_VENDOR, "IBM"); //$NON-NLS-1$
222
			properties.put(Constants.SERVICE_DESCRIPTION, MetaTypeMsg.SERVICE_DESCRIPTION);
223
			properties.put(Constants.SERVICE_PID, SERVICE_PID);
224
			MetaTypeServiceImpl service;
225
			synchronized (this) {
226
				service = metaTypeService = new MetaTypeServiceImpl(saxParserFactory, logService, mtpTracker);
227
			}
228
			bundleCtx.addBundleListener(service);
229
			ServiceRegistration<?> registration = bundleCtx.registerService(new String[] {MetaTypeService.class.getName(), EquinoxMetaTypeService.class.getName()}, service, properties);
230
			synchronized (this) {
231
				metaTypeServiceRegistration = registration;
232
			}
233
		}
234
235
		private boolean supportsNamespaceAwareness(SAXParserFactory factory) {
236
			if (factory.isNamespaceAware())
237
				return true;
238
			factory.setNamespaceAware(true);
239
			try {
240
				factory.newSAXParser();
241
				return true;
242
			} catch (Exception e) {
243
				return false;
244
			} finally {
245
				// Go back to the original settings.
246
				factory.setNamespaceAware(false);
247
			}
248
		}
249
250
		private void unregisterMetaTypeService(ServiceRegistration<?> registration, MetaTypeServiceImpl service) {
251
			registration.unregister();
252
			bundleCtx.removeBundleListener(service);
253
		}
254
	}
255
}
(-)src/org/eclipse/equinox/metatype/impl/AttributeDefinitionImpl.java (+311 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype.impl;
12
13
import org.eclipse.equinox.metatype.EquinoxAttributeDefinition;
14
15
import java.util.*;
16
import org.eclipse.osgi.util.NLS;
17
import org.osgi.service.log.LogService;
18
19
/**
20
 * Implementation of AttributeDefintion
21
 */
22
public class AttributeDefinitionImpl extends LocalizationElement implements EquinoxAttributeDefinition, Cloneable {
23
24
	String _name;
25
	String _id;
26
	String _description;
27
	int _cardinality = 0;
28
	int _dataType;
29
	Object _minValue = null;
30
	Object _maxValue = null;
31
	boolean _isRequired = true;
32
33
	String[] _defaults = null;
34
	Vector<String> _values = new Vector<String>(7);
35
	Vector<String> _labels = new Vector<String>(7);
36
37
	private final LogService logger;
38
	private final ExtendableHelper helper;
39
40
	/**
41
	 * Constructor of class AttributeDefinitionImpl.
42
	 */
43
	public AttributeDefinitionImpl(String id, String name, String description, int type, int cardinality, Object min, Object max, boolean isRequired, String localization, LogService logger, Map<String, Map<String, String>> extensionAttributes) {
44
		this(id, name, description, type, cardinality, min, max, isRequired, localization, logger, new ExtendableHelper(extensionAttributes));
45
	}
46
47
	private AttributeDefinitionImpl(String id, String name, String description, int type, int cardinality, Object min, Object max, boolean isRequired, String localization, LogService logger, ExtendableHelper helper) {
48
		this._id = id;
49
		this._name = name;
50
		this._description = description;
51
		this._dataType = type;
52
		this._cardinality = cardinality;
53
		this._minValue = min;
54
		this._maxValue = max;
55
		this._isRequired = isRequired;
56
		this._localization = localization;
57
		this.logger = logger;
58
		this.helper = helper;
59
	}
60
61
	/*
62
	 * 
63
	 */
64
	public synchronized Object clone() {
65
66
		AttributeDefinitionImpl ad = new AttributeDefinitionImpl(_id, _name, _description, _dataType, _cardinality, _minValue, _maxValue, _isRequired, _localization, logger, helper);
67
68
		if (_defaults != null) {
69
			ad.setDefaultValue(_defaults.clone());
70
		}
71
		if ((_labels != null) && (_values != null)) {
72
			@SuppressWarnings("unchecked")
73
			Vector<String> labels = (Vector<String>) _labels.clone();
74
			@SuppressWarnings("unchecked")
75
			Vector<String> values = (Vector<String>) _values.clone();
76
			ad.setOption(labels, values, false);
77
		}
78
79
		return ad;
80
	}
81
82
	/*
83
	 * (non-Javadoc)
84
	 * 
85
	 * @see org.osgi.service.metatype.AttributeDefinition#getName()
86
	 */
87
	public String getName() {
88
		return getLocalized(_name);
89
	}
90
91
	/**
92
	 * Method to set the name of AttributeDefinition.
93
	 */
94
	void setName(String name) {
95
		this._name = name;
96
	}
97
98
	/*
99
	 * (non-Javadoc)
100
	 * 
101
	 * @see org.osgi.service.metatype.AttributeDefinition#getID()
102
	 */
103
	public String getID() {
104
		return _id;
105
	}
106
107
	/**
108
	 * Method to set the ID of AttributeDefinition.
109
	 */
110
	void setID(String id) {
111
		this._id = id;
112
	}
113
114
	/*
115
	 * (non-Javadoc)
116
	 * 
117
	 * @see org.osgi.service.metatype.AttributeDefinition#getDescription()
118
	 */
119
	public String getDescription() {
120
		return getLocalized(_description);
121
	}
122
123
	/**
124
	 * Method to set the description of AttributeDefinition.
125
	 */
126
	void setDescription(String description) {
127
		this._description = description;
128
	}
129
130
	/*
131
	 * (non-Javadoc)
132
	 * 
133
	 * @see org.osgi.service.metatype.AttributeDefinition#getCardinality()
134
	 */
135
	public int getCardinality() {
136
		return _cardinality;
137
	}
138
139
	/**
140
	 * Method to set the cardinality of AttributeDefinition.
141
	 */
142
	void setCardinality(int cardinality) {
143
		this._cardinality = cardinality;
144
	}
145
146
	/*
147
	 * (non-Javadoc)
148
	 * 
149
	 * @see org.osgi.service.metatype.AttributeDefinition#getType()
150
	 */
151
	public int getType() {
152
		return _dataType;
153
	}
154
155
	/**
156
	 * Method to set the data type of AttributeDefinition.
157
	 */
158
	void setType(int type) {
159
		this._dataType = type;
160
	}
161
162
	/**
163
	 * Method to get the required flag of AttributeDefinition.
164
	 */
165
	boolean isRequired() {
166
		return _isRequired;
167
	}
168
169
	/**
170
	 * Method to set the required flag of AttributeDefinition.
171
	 */
172
	void setRequired(boolean isRequired) {
173
		this._isRequired = isRequired;
174
	}
175
176
	/*
177
	 * (non-Javadoc)
178
	 * 
179
	 * @see org.osgi.service.metatype.AttributeDefinition#getOptionLabels()
180
	 */
181
	public String[] getOptionLabels() {
182
183
		if ((_labels == null) || (_labels.size() == 0)) {
184
			return null;
185
		}
186
187
		String[] returnedLabels = new String[_labels.size()];
188
		Enumeration<String> labelKeys = _labels.elements();
189
		int i = 0;
190
		while (labelKeys.hasMoreElements()) {
191
			String labelKey = labelKeys.nextElement();
192
			returnedLabels[i] = getLocalized(labelKey);
193
			i++;
194
		}
195
		return returnedLabels;
196
	}
197
198
	/*
199
	 * (non-Javadoc)
200
	 * 
201
	 * @see org.osgi.service.metatype.AttributeDefinition#getOptionValues()
202
	 */
203
	public String[] getOptionValues() {
204
205
		if ((_values == null) || (_values.size() == 0)) {
206
			return null;
207
		}
208
209
		return _values.toArray(new String[_values.size()]);
210
	}
211
212
	/**
213
	 * Method to set the Option values of AttributeDefinition.
214
	 */
215
	void setOption(Vector<String> labels, Vector<String> values, boolean needValidation) {
216
		if ((labels == null) || (values == null)) {
217
			logger.log(LogService.LOG_ERROR, "AttributeDefinitionImpl.setOption(Vector, Vector, boolean) " + MetaTypeMsg.NULL_OPTIONS); //$NON-NLS-1$
218
			return;
219
		}
220
		if (labels.size() != values.size()) {
221
			logger.log(LogService.LOG_ERROR, "AttributeDefinitionImpl.setOption(Vector, Vector, boolean) " + MetaTypeMsg.INCONSISTENT_OPTIONS); //$NON-NLS-1$
222
			return;
223
		}
224
		_labels = labels;
225
		_values = values;
226
		if (needValidation) {
227
			for (int index = 0; index < _values.size(); index++) {
228
				ValueTokenizer vt = new ValueTokenizer(_values.get(index), logger);
229
				_values.set(index, vt.getValuesAsString());
230
				String reason = vt.validate(this);
231
				if ((reason != null) && reason.length() > 0) {
232
					logger.log(LogService.LOG_WARNING, NLS.bind(MetaTypeMsg.INVALID_OPTIONS, _values.get(index), reason));
233
					_labels.remove(index);
234
					_values.remove(index);
235
					index--; // Because this one has been removed.
236
				}
237
			}
238
		}
239
	}
240
241
	/*
242
	 * (non-Javadoc)
243
	 * 
244
	 * @see org.osgi.service.metatype.AttributeDefinition#getDefaultValue()
245
	 */
246
	public String[] getDefaultValue() {
247
		return _defaults;
248
	}
249
250
	/**
251
	 * Method to set the default value of AttributeDefinition.
252
	 * The given parameter is a comma delimited list needed to be parsed.
253
	 */
254
	void setDefaultValue(String defaults_str, boolean needValidation) {
255
		ValueTokenizer vt = new ValueTokenizer(defaults_str, logger);
256
		String reason = vt.validate(this);
257
		if ((reason != null) && reason.length() > 0) {
258
			logger.log(LogService.LOG_WARNING, NLS.bind(MetaTypeMsg.INVALID_DEFAULTS, vt.getValuesAsString(), reason));
259
			return;
260
		}
261
		setDefaultValue(vt.getValuesAsArray());
262
	}
263
264
	/**
265
	 * Method to set the default value of AttributeDefinition.
266
	 * The given parameter is a String array of multi values.
267
	 */
268
	void setDefaultValue(String[] defaults) {
269
		_defaults = defaults;
270
	}
271
272
	/**
273
	 * Method to set the validation value - min of AttributeDefinition.
274
	 */
275
	void setMinValue(Object minValue) {
276
		this._minValue = minValue;
277
	}
278
279
	/**
280
	 * Method to set the validation value - max of AttributeDefinition.
281
	 */
282
	void setMaxValue(Object maxValue) {
283
		this._maxValue = maxValue;
284
	}
285
286
	/*
287
	 * (non-Javadoc)
288
	 * In order to be valid, a value must pass all of the following tests.
289
	 * (1) The value must not be null.
290
	 * (2) The value must be convertible into the attribute definition's type.
291
	 * (3) The following relation must hold: min <= value <= max, if either min or max was specified.
292
	 * (4) If options were specified, the value must be equal to one of them.
293
	 * 
294
	 * Note this method will never return null to indicate there's no validation
295
	 * present. The type compatibility check can always be performed.
296
	 * 
297
	 * @see org.osgi.service.metatype.AttributeDefinition#validate(java.lang.String)
298
	 */
299
	public String validate(String value) {
300
		ValueTokenizer vt = new ValueTokenizer(value, logger);
301
		return vt.validate(this);
302
	}
303
304
	public Map<String, String> getExtensionAttributes(String schema) {
305
		return helper.getExtensionAttributes(schema);
306
	}
307
308
	public Set<String> getExtensionUris() {
309
		return helper.getExtensionUris();
310
	}
311
}
(-)src/org/eclipse/equinox/metatype/impl/DataParser.java (+849 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype.impl;
12
13
import java.io.*;
14
import java.math.BigDecimal;
15
import java.math.BigInteger;
16
import java.net.URL;
17
import java.util.*;
18
import javax.xml.parsers.SAXParser;
19
import org.eclipse.osgi.util.NLS;
20
import org.osgi.framework.Bundle;
21
import org.osgi.service.log.LogService;
22
import org.osgi.service.metatype.AttributeDefinition;
23
import org.xml.sax.*;
24
import org.xml.sax.helpers.DefaultHandler;
25
26
/**
27
 * Meta XML Data Parser
28
 */
29
public class DataParser {
30
	private static final String METADATA = "MetaData"; //$NON-NLS-1$
31
	private static final String LOCALIZATION = "localization"; //$NON-NLS-1$
32
	private static final String OCD = "OCD"; //$NON-NLS-1$
33
	private static final String ICON = "Icon"; //$NON-NLS-1$
34
	private static final String AD = "AD"; //$NON-NLS-1$
35
	private static final String CARDINALITY = "cardinality"; //$NON-NLS-1$
36
	private static final String OPTION = "Option"; //$NON-NLS-1$
37
	private static final String LABEL = "label"; //$NON-NLS-1$
38
	private static final String VALUE = "value"; //$NON-NLS-1$
39
	private static final String MIN = "min"; //$NON-NLS-1$
40
	private static final String MAX = "max"; //$NON-NLS-1$
41
	private static final String TYPE = "type"; //$NON-NLS-1$
42
	private static final String SIZE = "size"; //$NON-NLS-1$
43
	private static final String ID = "id"; //$NON-NLS-1$
44
	private static final String NAME = "name"; //$NON-NLS-1$
45
	private static final String DESCRIPTION = "description"; //$NON-NLS-1$
46
	private static final String RESOURCE = "resource"; //$NON-NLS-1$
47
	private static final String PID = "pid"; //$NON-NLS-1$
48
	private static final String DEFAULT = "default"; //$NON-NLS-1$
49
	private static final String ADREF = "adref"; //$NON-NLS-1$
50
	private static final String CONTENT = "content"; //$NON-NLS-1$
51
	private static final String FACTORY = "factoryPid"; //$NON-NLS-1$
52
	private static final String BUNDLE = "bundle"; //$NON-NLS-1$
53
	private static final String OPTIONAL = "optional"; //$NON-NLS-1$
54
	private static final String OBJECT = "Object"; //$NON-NLS-1$
55
	private static final String OCDREF = "ocdref"; //$NON-NLS-1$
56
	private static final String ATTRIBUTE = "Attribute"; //$NON-NLS-1$
57
	private static final String DESIGNATE = "Designate"; //$NON-NLS-1$
58
	private static final String MERGE = "merge"; //$NON-NLS-1$
59
	private static final String REQUIRED = "required"; //$NON-NLS-1$
60
61
	private static final String INTEGER = "Integer"; //$NON-NLS-1$
62
	private static final String STRING = "String"; //$NON-NLS-1$
63
	private static final String FLOAT = "Float"; //$NON-NLS-1$
64
	private static final String DOUBLE = "Double"; //$NON-NLS-1$
65
	private static final String BYTE = "Byte"; //$NON-NLS-1$
66
	private static final String LONG = "Long"; //$NON-NLS-1$
67
	private static final String CHAR = "Char"; //$NON-NLS-1$
68
	private static final String BOOLEAN = "Boolean"; //$NON-NLS-1$
69
	private static final String SHORT = "Short"; //$NON-NLS-1$
70
	private static final String PASSWORD = "Password"; //$NON-NLS-1$
71
72
	protected Bundle _dp_bundle;
73
	protected URL _dp_url;
74
	protected SAXParser _dp_parser;
75
	protected XMLReader _dp_xmlReader;
76
77
	// DesignateHanders in DataParser class
78
	Vector<DesignateHandler> _dp_designateHandlers = new Vector<DesignateHandler>(7);
79
	// ObjectClassDefinitions in DataParser class w/ corresponding reference keys
80
	Hashtable<String, ObjectClassDefinitionImpl> _dp_OCDs = new Hashtable<String, ObjectClassDefinitionImpl>(7);
81
	// Localization in DataParser class
82
	String _dp_localization;
83
84
	// Default visibility to avoid a plethora of synthetic accessor method warnings.
85
	final LogService logger;
86
	final Collection<Designate> designates = new ArrayList<Designate>(7);
87
88
	/*
89
	 * Constructor of class DataParser.
90
	 */
91
	public DataParser(Bundle bundle, URL url, SAXParser parser, LogService logger) {
92
93
		this._dp_bundle = bundle;
94
		this._dp_url = url;
95
		this._dp_parser = parser;
96
		this.logger = logger;
97
	}
98
99
	/*
100
	 * Main method to parse specific MetaData file.
101
	 */
102
	public Collection<Designate> doParse() throws IOException, SAXException {
103
		_dp_xmlReader = _dp_parser.getXMLReader();
104
		_dp_xmlReader.setContentHandler(new RootHandler());
105
		_dp_xmlReader.setErrorHandler(new MyErrorHandler(System.err));
106
		InputStream is = _dp_url.openStream();
107
		InputSource isource = new InputSource(is);
108
		logger.log(LogService.LOG_DEBUG, "Starting to parse " + _dp_url); //$NON-NLS-1$					
109
		_dp_xmlReader.parse(isource);
110
		return designates;
111
	}
112
113
	/*
114
	 * Convert String for expected data type.
115
	 */
116
	static Object convert(String value, int type) {
117
118
		if (value == null) {
119
			return null;
120
		}
121
122
		switch (type) {
123
		// PASSWORD should be treated like STRING.
124
			case AttributeDefinition.PASSWORD :
125
			case AttributeDefinition.STRING :
126
				// Both the min and max of STRING are Integers.
127
				return new Integer(value);
128
			case AttributeDefinition.LONG :
129
				return new Long(value);
130
			case AttributeDefinition.INTEGER :
131
				return new Integer(value);
132
			case AttributeDefinition.SHORT :
133
				return new Short(value);
134
			case AttributeDefinition.CHARACTER :
135
				return new Character(value.charAt(0));
136
			case AttributeDefinition.BYTE :
137
				return new Byte(value);
138
			case AttributeDefinition.DOUBLE :
139
				return new Double(value);
140
			case AttributeDefinition.FLOAT :
141
				return new Float(value);
142
			case AttributeDefinition.BIGINTEGER :
143
				return new BigInteger(value);
144
			case AttributeDefinition.BIGDECIMAL :
145
				return new BigDecimal(value);
146
			case AttributeDefinition.BOOLEAN :
147
				return new Boolean(value);
148
			default :
149
				// Unknown data type
150
				return null;
151
		}
152
	}
153
154
	/**
155
	 * Abstract of all Handlers.
156
	 */
157
	private class AbstractHandler extends DefaultHandler {
158
		protected ContentHandler _doc_handler;
159
		protected boolean _isParsedDataValid = true;
160
		protected Map<String, Map<String, String>> extensionAttributes = new HashMap<String, Map<String, String>>();
161
162
		public AbstractHandler(ContentHandler parentHandler) {
163
			this._doc_handler = parentHandler;
164
			_dp_xmlReader.setContentHandler(this);
165
		}
166
167
		public void endElement(String namespaceURI, String localName, String qName) {
168
			finished();
169
			// Let parent resume handling SAX events
170
			_dp_xmlReader.setContentHandler(_doc_handler);
171
		}
172
173
		public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
174
			throw new SAXException(NLS.bind(MetaTypeMsg.UNEXPECTED_ELEMENT, qName));
175
		}
176
177
		public void characters(char[] buf, int start, int end) throws SAXException {
178
			String s = new String(buf, start, end).trim();
179
			if (s.length() > 0) {
180
				throw new SAXException(NLS.bind(MetaTypeMsg.UNEXPECTED_TEXT, s));
181
			}
182
		}
183
184
		protected void collectExtensionAttributes(Attributes attributes) {
185
			for (int i = 0; i < attributes.getLength(); i++) {
186
				String key = attributes.getURI(i);
187
				if (key.length() == 0 || key.startsWith("http://www.osgi.org/xmlns/metatype/v")) //$NON-NLS-1$
188
					continue;
189
				Map<String, String> value = extensionAttributes.get(key);
190
				if (value == null) {
191
					value = new HashMap<String, String>();
192
					extensionAttributes.put(key, value);
193
				}
194
				value.put(getName(attributes.getLocalName(i), attributes.getQName(i)), attributes.getValue(i));
195
			}
196
		}
197
198
		/**
199
		 * Called when this element and all elements nested into it have been
200
		 * handled.
201
		 */
202
		protected void finished() {
203
			// do nothing by default
204
		}
205
	}
206
207
	/**
208
	 * Handler for the root element.
209
	 */
210
	private class RootHandler extends DefaultHandler {
211
212
		public RootHandler() {
213
			super();
214
		}
215
216
		public void startElement(String uri, String localName, String qName, Attributes attributes) {
217
218
			logger.log(LogService.LOG_DEBUG, "Here is AbstractHandler:startElement():" //$NON-NLS-1$
219
					+ qName);
220
			String name = getName(localName, qName);
221
			if (name.equalsIgnoreCase(METADATA)) {
222
				new MetaDataHandler(this).init(name, attributes);
223
			} else {
224
				logger.log(LogService.LOG_WARNING, NLS.bind(MetaTypeMsg.UNEXPECTED_ELEMENT, name));
225
			}
226
		}
227
228
		public void setDocumentLocator(Locator locator) {
229
			// do nothing
230
		}
231
	}
232
233
	/**
234
	 * Handler for the MetaData element.
235
	 */
236
	private class MetaDataHandler extends AbstractHandler {
237
238
		public MetaDataHandler(ContentHandler handler) {
239
			super(handler);
240
		}
241
242
		public void init(String name, Attributes attributes) {
243
244
			logger.log(LogService.LOG_DEBUG, "Here is MetaDataHandler():init()"); //$NON-NLS-1$
245
			_dp_localization = attributes.getValue(LOCALIZATION);
246
			if (_dp_localization == null) {
247
				// Not a problem, because LOCALIZATION is an optional attribute.
248
			}
249
			// The global variable "_dp_localization" will be used within
250
			// OcdHandler and AttributeDefinitionHandler later.
251
		}
252
253
		public void startElement(String uri, String localName, String qName, Attributes atts) {
254
255
			logger.log(LogService.LOG_DEBUG, "Here is MetaDataHandler:startElement():" //$NON-NLS-1$
256
					+ qName);
257
			String name = getName(localName, qName);
258
			if (name.equalsIgnoreCase(DESIGNATE)) {
259
				DesignateHandler designateHandler = new DesignateHandler(this);
260
				designateHandler.init(name, atts);
261
				if (designateHandler._isParsedDataValid) {
262
					_dp_designateHandlers.addElement(designateHandler);
263
				}
264
			} else if (name.equalsIgnoreCase(OCD)) {
265
				OcdHandler ocdHandler = new OcdHandler(this);
266
				ocdHandler.init(name, atts, _dp_OCDs);
267
			} else {
268
				logger.log(LogService.LOG_WARNING, NLS.bind(MetaTypeMsg.UNEXPECTED_ELEMENT, name));
269
			}
270
		}
271
272
		protected void finished() {
273
274
			logger.log(LogService.LOG_DEBUG, "Here is MetaDataHandler():finished()"); //$NON-NLS-1$
275
			if (_dp_designateHandlers.size() == 0) {
276
				// Schema defines at least one DESIGNATE is required.
277
				_isParsedDataValid = false;
278
				logger.log(LogService.LOG_WARNING, "DataParser.finished() " + NLS.bind(MetaTypeMsg.MISSING_ELEMENT, DESIGNATE)); //$NON-NLS-1$
279
				return;
280
			}
281
			Enumeration<DesignateHandler> designateHandlerKeys = _dp_designateHandlers.elements();
282
			while (designateHandlerKeys.hasMoreElements()) {
283
				DesignateHandler dh = designateHandlerKeys.nextElement();
284
285
				ObjectClassDefinitionImpl ocd = _dp_OCDs.get(dh._ocdref);
286
				if (ocd != null) {
287
					designates.add(new Designate.Builder(ocd).bundle(dh._bundle_val).factoryPid(dh._factory_val).merge(dh._merge_val).pid(dh._pid_val).optional(dh._optional_val).build());
288
				} else {
289
					logger.log(LogService.LOG_ERROR, "DataParser.finished() " + NLS.bind(MetaTypeMsg.OCD_ID_NOT_FOUND, dh._ocdref)); //$NON-NLS-1$
290
291
				}
292
			}
293
		}
294
	}
295
296
	/**
297
	 * Handler for the ObjectClassDefinition element.
298
	 */
299
	private class OcdHandler extends AbstractHandler {
300
301
		Hashtable<String, ObjectClassDefinitionImpl> _parent_OCDs_hashtable;
302
		// This ID "_refID" is only used for reference by Designate element,
303
		// not the PID or FPID of this OCD.
304
		String _refID;
305
		ObjectClassDefinitionImpl _ocd;
306
		Vector<AttributeDefinitionImpl> _ad_vector = new Vector<AttributeDefinitionImpl>(7);
307
308
		public OcdHandler(ContentHandler handler) {
309
			super(handler);
310
		}
311
312
		public void init(String name, Attributes atts, Hashtable<String, ObjectClassDefinitionImpl> ocds_hashtable) {
313
314
			logger.log(LogService.LOG_DEBUG, "Here is OcdHandler():init()"); //$NON-NLS-1$
315
			_parent_OCDs_hashtable = ocds_hashtable;
316
			collectExtensionAttributes(atts);
317
			String ocd_name_val = atts.getValue(NAME);
318
			if (ocd_name_val == null) {
319
				_isParsedDataValid = false;
320
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes, Hashtable) " + NLS.bind(MetaTypeMsg.MISSING_ATTRIBUTE, NAME, name)); //$NON-NLS-1$
321
				return;
322
			}
323
324
			String ocd_description_val = atts.getValue(DESCRIPTION);
325
			if (ocd_description_val == null) {
326
				// Not a problem, because DESCRIPTION is an optional attribute.
327
			}
328
329
			_refID = atts.getValue(ID);
330
			if (_refID == null) {
331
				_isParsedDataValid = false;
332
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes, Hashtable) " + NLS.bind(MetaTypeMsg.MISSING_ATTRIBUTE, ID, name)); //$NON-NLS-1$
333
				return;
334
			}
335
336
			_ocd = new ObjectClassDefinitionImpl(ocd_name_val, ocd_description_val, _refID, _dp_localization, extensionAttributes);
337
		}
338
339
		public void startElement(String uri, String localName, String qName, Attributes atts) {
340
341
			logger.log(LogService.LOG_DEBUG, "Here is OcdHandler:startElement():" //$NON-NLS-1$
342
					+ qName);
343
			if (!_isParsedDataValid)
344
				return;
345
346
			String name = getName(localName, qName);
347
			if (name.equalsIgnoreCase(AD)) {
348
				AttributeDefinitionHandler attributeDefHandler = new AttributeDefinitionHandler(this);
349
				attributeDefHandler.init(name, atts, _ad_vector);
350
			} else if (name.equalsIgnoreCase(ICON)) {
351
				IconHandler iconHandler = new IconHandler(this);
352
				iconHandler.init(name, atts);
353
				if (iconHandler._isParsedDataValid) {
354
					// Because XML schema allows at most one icon for
355
					// one OCD, if more than one icons are read from 
356
					// MetaData, then only the final icon will be kept.
357
					_ocd.setIcon(iconHandler._icon);
358
				}
359
			} else {
360
				logger.log(LogService.LOG_WARNING, NLS.bind(MetaTypeMsg.UNEXPECTED_ELEMENT, name));
361
			}
362
		}
363
364
		protected void finished() {
365
366
			logger.log(LogService.LOG_DEBUG, "Here is OcdHandler():finished()"); //$NON-NLS-1$
367
			if (!_isParsedDataValid)
368
				return;
369
370
			if (_ad_vector.size() == 0) {
371
				// Schema defines at least one AD is required.
372
				_isParsedDataValid = false;
373
				logger.log(LogService.LOG_ERROR, "DataParser.finished() " + NLS.bind(MetaTypeMsg.MISSING_ELEMENT, AD, _refID)); //$NON-NLS-1$
374
				return;
375
			}
376
			// OCD gets all parsed ADs.
377
			Enumeration<AttributeDefinitionImpl> adKey = _ad_vector.elements();
378
			while (adKey.hasMoreElements()) {
379
				AttributeDefinitionImpl ad = adKey.nextElement();
380
				_ocd.addAttributeDefinition(ad, ad._isRequired);
381
			}
382
383
			_parent_OCDs_hashtable.put(_refID, _ocd);
384
		}
385
	}
386
387
	/**
388
	 * Handler for the Icon element.
389
	 */
390
	private class IconHandler extends AbstractHandler {
391
392
		Icon _icon;
393
394
		public IconHandler(ContentHandler handler) {
395
			super(handler);
396
		}
397
398
		public void init(String name, Attributes atts) {
399
400
			logger.log(LogService.LOG_DEBUG, "Here is IconHandler:init()"); //$NON-NLS-1$
401
			String icon_resource_val = atts.getValue(RESOURCE);
402
			if (icon_resource_val == null) {
403
				_isParsedDataValid = false;
404
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes) " + NLS.bind(MetaTypeMsg.MISSING_ATTRIBUTE, RESOURCE, name)); //$NON-NLS-1$
405
				return;
406
			}
407
408
			String icon_size_val = atts.getValue(SIZE);
409
			if (icon_size_val == null) {
410
				// Not a problem, because SIZE is an optional attribute.
411
				icon_size_val = "0"; //$NON-NLS-1$
412
			} else if (icon_size_val.equalsIgnoreCase("")) { //$NON-NLS-1$
413
				icon_size_val = "0"; //$NON-NLS-1$
414
			}
415
416
			_icon = new Icon(icon_resource_val, Integer.parseInt(icon_size_val), _dp_bundle);
417
		}
418
	}
419
420
	/**
421
	 * Handler for the Attribute element.
422
	 */
423
	private class AttributeDefinitionHandler extends AbstractHandler {
424
425
		AttributeDefinitionImpl _ad;
426
		int _dataType;
427
428
		Vector<AttributeDefinitionImpl> _parent_ADs_vector;
429
		Vector<String> _optionLabel_vector = new Vector<String>(7);
430
		Vector<String> _optionValue_vector = new Vector<String>(7);
431
432
		public AttributeDefinitionHandler(ContentHandler handler) {
433
			super(handler);
434
		}
435
436
		public void init(String name, Attributes atts, Vector<AttributeDefinitionImpl> ad_vector) {
437
438
			logger.log(LogService.LOG_DEBUG, "Here is AttributeDefinitionHandler():init()"); //$NON-NLS-1$
439
			_parent_ADs_vector = ad_vector;
440
			collectExtensionAttributes(atts);
441
			String ad_name_val = atts.getValue(NAME);
442
			if (ad_name_val == null) {
443
				// Not a problem, because NAME is an optional attribute.
444
			}
445
446
			String ad_description_val = atts.getValue(DESCRIPTION);
447
			if (ad_description_val == null) {
448
				// Not a problem, because DESCRIPTION is an optional attribute.
449
			}
450
451
			String ad_id_val = atts.getValue(ID);
452
			if (ad_id_val == null) {
453
				_isParsedDataValid = false;
454
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes, Vector) " + NLS.bind(MetaTypeMsg.MISSING_ATTRIBUTE, ID, name)); //$NON-NLS-1$
455
				return;
456
			}
457
458
			String ad_type_val = atts.getValue(TYPE);
459
			if (ad_type_val == null) {
460
				_isParsedDataValid = false;
461
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes, Vector) " + NLS.bind(MetaTypeMsg.MISSING_ATTRIBUTE, TYPE, name)); //$NON-NLS-1$
462
				return;
463
			}
464
			if (ad_type_val.equalsIgnoreCase(STRING)) {
465
				_dataType = AttributeDefinition.STRING;
466
			} else if (ad_type_val.equalsIgnoreCase(LONG)) {
467
				_dataType = AttributeDefinition.LONG;
468
			} else if (ad_type_val.equalsIgnoreCase(DOUBLE)) {
469
				_dataType = AttributeDefinition.DOUBLE;
470
			} else if (ad_type_val.equalsIgnoreCase(FLOAT)) {
471
				_dataType = AttributeDefinition.FLOAT;
472
			} else if (ad_type_val.equalsIgnoreCase(INTEGER)) {
473
				_dataType = AttributeDefinition.INTEGER;
474
			} else if (ad_type_val.equalsIgnoreCase(BYTE)) {
475
				_dataType = AttributeDefinition.BYTE;
476
			} else if (ad_type_val.equalsIgnoreCase(CHAR)) {
477
				_dataType = AttributeDefinition.CHARACTER;
478
			} else if (ad_type_val.equalsIgnoreCase(BOOLEAN)) {
479
				_dataType = AttributeDefinition.BOOLEAN;
480
			} else if (ad_type_val.equalsIgnoreCase(SHORT)) {
481
				_dataType = AttributeDefinition.SHORT;
482
			} else if (ad_type_val.equalsIgnoreCase(PASSWORD)) {
483
				_dataType = AttributeDefinition.PASSWORD;
484
			} else {
485
				_isParsedDataValid = false;
486
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes, Vector) " + NLS.bind(MetaTypeMsg.INVALID_TYPE, new Object[] {ad_type_val, _dp_url, _dp_bundle.getBundleId()})); //$NON-NLS-1$
487
				return;
488
			}
489
490
			String ad_cardinality_str = atts.getValue(CARDINALITY);
491
			int ad_cardinality_val = 0;
492
			if (ad_cardinality_str == null) {
493
				// Not a problem, because CARDINALITY is an optional attribute.
494
				// And the default value is 0.
495
			} else {
496
				ad_cardinality_val = Integer.parseInt(ad_cardinality_str);
497
			}
498
499
			String ad_min_val = atts.getValue(MIN);
500
			if (ad_min_val == null) {
501
				// Not a problem, because MIN is an optional attribute.
502
			}
503
504
			String ad_max_val = atts.getValue(MAX);
505
			if (ad_max_val == null) {
506
				// Not a problem, because MAX is an optional attribute.
507
			}
508
509
			String ad_defaults_str = atts.getValue(DEFAULT);
510
			if (ad_defaults_str == null) {
511
				// Not a problem, because DEFAULT is an optional attribute.
512
			}
513
514
			String ad_required_val = atts.getValue(REQUIRED);
515
			if (ad_required_val == null) {
516
				// Not a problem, because REQUIRED is an optional attribute.
517
				// And the default value is 'true'.
518
				ad_required_val = Boolean.TRUE.toString();
519
			}
520
521
			_ad = new AttributeDefinitionImpl(ad_id_val, ad_name_val, ad_description_val, _dataType, ad_cardinality_val, convert(ad_min_val, _dataType), convert(ad_max_val, _dataType), Boolean.valueOf(ad_required_val).booleanValue(), _dp_localization, logger, extensionAttributes);
522
523
			if (ad_defaults_str != null) {
524
				_ad.setDefaultValue(ad_defaults_str, true);
525
			}
526
		}
527
528
		public void startElement(String uri, String localName, String qName, Attributes atts) {
529
530
			logger.log(LogService.LOG_DEBUG, "Here is AttributeDefinitionHandler:startElement():" //$NON-NLS-1$
531
					+ qName);
532
			if (!_isParsedDataValid)
533
				return;
534
535
			String name = getName(localName, qName);
536
			if (name.equalsIgnoreCase(OPTION)) {
537
				OptionHandler optionHandler = new OptionHandler(this);
538
				optionHandler.init(name, atts);
539
				if (optionHandler._isParsedDataValid) {
540
					// Only add valid Option
541
					_optionLabel_vector.addElement(optionHandler._label_val);
542
					_optionValue_vector.addElement(optionHandler._value_val);
543
				}
544
			} else {
545
				logger.log(LogService.LOG_WARNING, NLS.bind(MetaTypeMsg.UNEXPECTED_ELEMENT, name));
546
			}
547
		}
548
549
		protected void finished() {
550
551
			logger.log(LogService.LOG_DEBUG, "Here is AttributeDefinitionHandler():finished()"); //$NON-NLS-1$
552
			if (!_isParsedDataValid)
553
				return;
554
555
			_ad.setOption(_optionLabel_vector, _optionValue_vector, true);
556
			_parent_ADs_vector.addElement(_ad);
557
		}
558
	}
559
560
	/**
561
	 * Handler for the Option element.
562
	 */
563
	private class OptionHandler extends AbstractHandler {
564
565
		String _label_val;
566
		String _value_val;
567
568
		public OptionHandler(ContentHandler handler) {
569
			super(handler);
570
		}
571
572
		public void init(String name, Attributes atts) {
573
574
			logger.log(LogService.LOG_DEBUG, "Here is OptionHandler:init()"); //$NON-NLS-1$
575
			_label_val = atts.getValue(LABEL);
576
			if (_label_val == null) {
577
				_isParsedDataValid = false;
578
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes) " + NLS.bind(MetaTypeMsg.MISSING_ATTRIBUTE, LABEL, name)); //$NON-NLS-1$
579
				return;
580
			}
581
582
			_value_val = atts.getValue(VALUE);
583
			if (_value_val == null) {
584
				_isParsedDataValid = false;
585
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes) " + NLS.bind(MetaTypeMsg.MISSING_ATTRIBUTE, VALUE, name)); //$NON-NLS-1$
586
				return;
587
			}
588
		}
589
	}
590
591
	//	/**
592
	//	 * Handler for the Simple Value element.
593
	//	 */
594
	//	private class SimpleValueHandler extends AbstractHandler {
595
	//
596
	//		StringBuffer	_buffer	= new StringBuffer();
597
	//		Vector			_parent_value_vector;
598
	//		String			_elementName;
599
	//
600
	//		public SimpleValueHandler(ContentHandler handler) {
601
	//			super(handler);
602
	//		}
603
	//
604
	//		public void init(String name, Attributes atts, Vector value_vector)
605
	//				throws SAXException {
606
	//
607
	//			Logging.log(LogService.LOG_DEBUG,
608
	//					"Here is SimpleValueHandler():init()"); //$NON-NLS-1$
609
	//			_elementName = name;
610
	//			_parent_value_vector = value_vector;
611
	//		}
612
	//
613
	//		protected void finished() throws SAXException {
614
	//
615
	//			Logging.log(LogService.LOG_DEBUG,
616
	//					"Here is SimpleValueHandler():finished()"); //$NON-NLS-1$
617
	//			if (_parent_value_vector != null) {
618
	//				_parent_value_vector.addElement(_buffer.toString());
619
	//			}
620
	//		}
621
	//
622
	//		public void characters(char buf[], int offset, int len)
623
	//				throws SAXException {
624
	//
625
	//			Logging.log(LogService.LOG_DEBUG,
626
	//					"Here is SimpleValueHandler(" //$NON-NLS-1$
627
	//					+ _elementName
628
	//					+ "):characters():[" //$NON-NLS-1$
629
	//					+ new String(buf, offset, len)
630
	//					+ "]"); //$NON-NLS-1$
631
	//			_buffer.append(new String(buf, offset, len));
632
	//		}
633
	//	}
634
635
	/**
636
	 * Handler for the Designate element.
637
	 */
638
	class DesignateHandler extends AbstractHandler {
639
640
		String _pid_val = null;
641
		String _factory_val = null;
642
		String _bundle_val = null; // Only used by RFC94
643
		boolean _optional_val = false; // Only used by RFC94
644
		boolean _merge_val = false; // Only used by RFC94
645
646
		// Referenced OCD ID
647
		String _ocdref;
648
649
		public DesignateHandler(ContentHandler handler) {
650
			super(handler);
651
		}
652
653
		public void init(String name, Attributes atts) {
654
655
			logger.log(LogService.LOG_DEBUG, "Here is DesignateHandler():init()"); //$NON-NLS-1$
656
			_pid_val = atts.getValue(PID);
657
			_factory_val = atts.getValue(FACTORY);
658
			if (_pid_val == null && _factory_val == null) {
659
				_isParsedDataValid = false;
660
				logger.log(LogService.LOG_ERROR, MetaTypeMsg.MISSING_DESIGNATE_PID_AND_FACTORYPID);
661
				return;
662
			}
663
664
			_bundle_val = atts.getValue(BUNDLE);
665
			if (_bundle_val == null) {
666
				// Not a problem because BUNDLE is an optional attribute.
667
			}
668
669
			String optional_str = atts.getValue(OPTIONAL);
670
			if (optional_str == null) {
671
				// Not a problem, because OPTIONAL is an optional attribute.
672
				// The default value is "false".
673
				_optional_val = false;
674
			} else {
675
				_optional_val = Boolean.valueOf(optional_str).booleanValue();
676
			}
677
678
			String merge_str = atts.getValue(MERGE);
679
			if (merge_str == null) {
680
				// Not a problem, because MERGE is an optional attribute.
681
				// The default value is "false".
682
				_merge_val = false;
683
			} else {
684
				_merge_val = Boolean.valueOf(merge_str).booleanValue();
685
			}
686
		}
687
688
		public void startElement(String uri, String localName, String qName, Attributes atts) {
689
690
			logger.log(LogService.LOG_DEBUG, "Here is DesignateHandler:startElement():" //$NON-NLS-1$
691
					+ qName);
692
			if (!_isParsedDataValid)
693
				return;
694
695
			String name = getName(localName, qName);
696
			if (name.equalsIgnoreCase(OBJECT)) {
697
				ObjectHandler objectHandler = new ObjectHandler(this);
698
				objectHandler.init(name, atts);
699
				if (objectHandler._isParsedDataValid) {
700
					_ocdref = objectHandler._ocdref;
701
				}
702
			} else {
703
				logger.log(LogService.LOG_WARNING, NLS.bind(MetaTypeMsg.UNEXPECTED_ELEMENT, name));
704
			}
705
		}
706
707
		protected void finished() {
708
709
			logger.log(LogService.LOG_DEBUG, "Here is DesignateHandler():finished()"); //$NON-NLS-1$
710
			if (!_isParsedDataValid)
711
				return;
712
713
			if (_ocdref == null) {
714
				_isParsedDataValid = false;
715
				// Schema defines at least one OBJECT is required.
716
				logger.log(LogService.LOG_ERROR, "DataParser.finished() " + NLS.bind(MetaTypeMsg.MISSING_ELEMENT, OBJECT, _pid_val)); //$NON-NLS-1$
717
				return;
718
719
			}
720
		}
721
	}
722
723
	/**
724
	 * Handler for the Object element.
725
	 */
726
	private class ObjectHandler extends AbstractHandler {
727
728
		String _ocdref;
729
730
		public ObjectHandler(ContentHandler handler) {
731
			super(handler);
732
		}
733
734
		public void init(String name, Attributes atts) {
735
736
			logger.log(LogService.LOG_DEBUG, "Here is ObjectHandler():init()"); //$NON-NLS-1$
737
			_ocdref = atts.getValue(OCDREF);
738
			if (_ocdref == null) {
739
				_isParsedDataValid = false;
740
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes) " + NLS.bind(MetaTypeMsg.MISSING_ATTRIBUTE, OCDREF, name)); //$NON-NLS-1$
741
				return;
742
			}
743
		}
744
745
		public void startElement(String uri, String localName, String qName, Attributes atts) {
746
747
			logger.log(LogService.LOG_DEBUG, "Here is ObjectHandler:startElement():" //$NON-NLS-1$
748
					+ qName);
749
			if (!_isParsedDataValid)
750
				return;
751
752
			String name = getName(localName, qName);
753
			if (name.equalsIgnoreCase(ATTRIBUTE)) {
754
				AttributeHandler attributeHandler = new AttributeHandler(this);
755
				attributeHandler.init(name, atts);
756
				// The ATTRIBUTE element is only used by RFC94, do nothing for it here.
757
			} else {
758
				logger.log(LogService.LOG_WARNING, NLS.bind(MetaTypeMsg.UNEXPECTED_ELEMENT, name));
759
			}
760
		}
761
	}
762
763
	/**
764
	 * Handler for the Attribute element.
765
	 * 
766
	 * This Handler is only used by RFC94.
767
	 */
768
	private class AttributeHandler extends AbstractHandler {
769
770
		String _adref_val;
771
		String _content_val;
772
773
		public AttributeHandler(ContentHandler handler) {
774
			super(handler);
775
		}
776
777
		public void init(String name, Attributes atts) {
778
779
			logger.log(LogService.LOG_DEBUG, "Here is AttributeHandler():init()"); //$NON-NLS-1$
780
			_adref_val = atts.getValue(ADREF);
781
			if (_adref_val == null) {
782
				_isParsedDataValid = false;
783
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes) " + NLS.bind(MetaTypeMsg.MISSING_ATTRIBUTE, ADREF, name)); //$NON-NLS-1$
784
				return;
785
			}
786
787
			_content_val = atts.getValue(CONTENT);
788
			if (_content_val == null) {
789
				_isParsedDataValid = false;
790
				logger.log(LogService.LOG_ERROR, "DataParser.init(String, Attributes) " + NLS.bind(MetaTypeMsg.MISSING_ATTRIBUTE, CONTENT, name)); //$NON-NLS-1$
791
				return;
792
			}
793
		}
794
	}
795
796
	/**
797
	 * Error Handler to report errors and warnings
798
	 */
799
	private static class MyErrorHandler implements ErrorHandler {
800
801
		/** Error handler output goes here */
802
		private PrintStream _out;
803
804
		MyErrorHandler(PrintStream out) {
805
			this._out = out;
806
		}
807
808
		/**
809
		 * Returns a string describing parse exception details
810
		 */
811
		private String getParseExceptionInfo(SAXParseException spe) {
812
			String systemId = spe.getSystemId();
813
			if (systemId == null) {
814
				systemId = "null"; //$NON-NLS-1$
815
			}
816
			String info = "URI=" + systemId + //$NON-NLS-1$
817
					" Line=" + spe.getLineNumber() + //$NON-NLS-1$
818
					": " + spe.getMessage(); //$NON-NLS-1$
819
820
			return info;
821
		}
822
823
		// The following methods are standard SAX ErrorHandler methods.
824
		// See SAX documentation for more info.
825
826
		public void warning(SAXParseException spe) {
827
			_out.println("Warning: " + getParseExceptionInfo(spe)); //$NON-NLS-1$
828
		}
829
830
		public void error(SAXParseException spe) throws SAXException {
831
			String message = "Error: " + getParseExceptionInfo(spe); //$NON-NLS-1$
832
			throw new SAXException(message);
833
		}
834
835
		public void fatalError(SAXParseException spe) throws SAXException {
836
			String message = "Fatal Error: " + getParseExceptionInfo(spe); //$NON-NLS-1$
837
			throw new SAXException(message);
838
		}
839
	}
840
841
	public static String getName(String localName, String qName) {
842
		if (localName != null && localName.length() > 0) {
843
			return localName;
844
		}
845
846
		int nameSpaceIndex = qName.indexOf(":"); //$NON-NLS-1$
847
		return nameSpaceIndex == -1 ? qName : qName.substring(nameSpaceIndex + 1);
848
	}
849
}
(-)src/org/eclipse/equinox/metatype/impl/Designate.java (+104 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype.impl;
12
13
import org.eclipse.osgi.util.NLS;
14
15
public class Designate {
16
	public static class Builder {
17
		String bundle;
18
		String factoryPid;
19
		boolean merge;
20
		ObjectClassDefinitionImpl ocd;
21
		boolean optional;
22
		String pid;
23
24
		public Builder(ObjectClassDefinitionImpl ocd) {
25
			if (ocd == null) {
26
				throw new IllegalArgumentException(NLS.bind(MetaTypeMsg.MISSING_REQUIRED_PARAMETER, "ocd")); //$NON-NLS-1$
27
			}
28
			this.ocd = ocd;
29
		}
30
31
		public Designate build() {
32
			return new Designate(this);
33
		}
34
35
		public Builder bundle(String value) {
36
			bundle = value;
37
			return this;
38
		}
39
40
		public Builder factoryPid(String value) {
41
			factoryPid = value;
42
			return this;
43
		}
44
45
		public Builder merge(boolean value) {
46
			merge = value;
47
			return this;
48
		}
49
50
		public Builder optional(boolean value) {
51
			optional = value;
52
			return this;
53
		}
54
55
		public Builder pid(String value) {
56
			pid = value;
57
			return this;
58
		}
59
	}
60
61
	private final String bundle;
62
	private final String factoryPid;
63
	private final boolean merge;
64
	private final ObjectClassDefinitionImpl ocd;
65
	private final boolean optional;
66
	private final String pid;
67
68
	Designate(Builder b) {
69
		bundle = b.bundle;
70
		factoryPid = b.factoryPid;
71
		merge = b.merge;
72
		ocd = b.ocd;
73
		optional = b.optional;
74
		pid = b.pid;
75
	}
76
77
	public String getBundle() {
78
		return bundle;
79
	}
80
81
	public String getFactoryPid() {
82
		return factoryPid;
83
	}
84
85
	public boolean isFactory() {
86
		return factoryPid != null && factoryPid.length() != 0;
87
	}
88
89
	public boolean isMerge() {
90
		return merge;
91
	}
92
93
	public ObjectClassDefinitionImpl getObjectClassDefinition() {
94
		return ocd;
95
	}
96
97
	public boolean isOptional() {
98
		return optional;
99
	}
100
101
	public String getPid() {
102
		return pid;
103
	}
104
}
(-)src/org/eclipse/equinox/metatype/impl/ExtendableHelper.java (+39 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 IBM Corporation and others
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype.impl;
12
13
import org.eclipse.equinox.metatype.Extendable;
14
15
import java.util.*;
16
17
public class ExtendableHelper implements Extendable {
18
	private final Map<String, Map<String, String>> attributes;
19
20
	@SuppressWarnings("unchecked")
21
	public ExtendableHelper() {
22
		this(Collections.EMPTY_MAP);
23
	}
24
25
	public ExtendableHelper(Map<String, Map<String, String>> attributes) {
26
		if (attributes == null)
27
			throw new NullPointerException();
28
		this.attributes = attributes;
29
	}
30
31
	public Map<String, String> getExtensionAttributes(String schema) {
32
		return Collections.unmodifiableMap(attributes.get(schema));
33
	}
34
35
	public Set<String> getExtensionUris() {
36
		return Collections.unmodifiableSet(attributes.keySet());
37
	}
38
39
}
(-)src/org/eclipse/equinox/metatype/impl/ExternalMessages.properties (+37 lines)
Added Link Here
1
###############################################################################
2
# Copyright (c) 2005, 2011 IBM Corporation.
3
# All rights reserved. This program and the accompanying materials
4
# are made available under the terms of the Eclipse Public License v1.0
5
# which accompanies this distribution, and is available at
6
# http://www.eclipse.org/legal/epl-v10.html
7
#
8
# Contributors:
9
#     IBM Corporation - initial API and implementation
10
###############################################################################
11
#External Messages for EN locale
12
SERVICE_DESCRIPTION=OSGi Metatype Service - IBM Implementation
13
14
UNEXPECTED_ELEMENT=Unexpected element {0}.
15
UNEXPECTED_TEXT=Unexpected text {0}.
16
MISSING_ATTRIBUTE=Missing attribute {0} in tag {1}.
17
INVALID_TYPE=Invalid attribute definition type {0} in metadata XML at {1} for bundle ID {2}.
18
MISSING_DESIGNATE_PID_AND_FACTORYPID=A <Designate> element must specify either the 'pid' or 'factoryPid' attribute.
19
OCD_ID_NOT_FOUND=Object Class Definition ID not found {0}.
20
MISSING_ELEMENT=Missing element {0} (Reference ID = {1}.
21
22
EXCEPTION_MESSAGE=Unexpected exception {0} with message {1}.
23
NULL_IS_INVALID=Cannot validate a null.
24
VALUE_OUT_OF_RANGE=Value {0} is out of range.
25
VALUE_OUT_OF_OPTION=Value {0} is out of Option.
26
CARDINALITY_VIOLATION=Cardinality violation: \"{0}\" has {1} value(s) but must have between {2} and {3} value(s).
27
NULL_OPTIONS=Cannot set Option labels or values as null.
28
INCONSISTENT_OPTIONS=Labels and Values of Option have different sizes.
29
INVALID_OPTIONS=Option value {0} is invalid because of {1}.
30
INVALID_DEFAULTS=Dafaults value {0} is invalid because of {1}.
31
32
METADATA_NOT_FOUND=Bundle(ID=\"{0}\", name=\"{1}\") has no MetaData file.
33
ASK_INVALID_LOCALE=OCD(ID=\"{0}\") cannot support this locale \"{1}\".
34
MISSING_REQUIRED_PARAMETER=Missing required parameter: {0}
35
TOKENIZER_GOT_INVALID_DATA=The Tokenizer got invalid data.
36
INVALID_PID_METATYPE_PROVIDER_IGNORED=Bundle {0} with ID {1} provided a MetaTypeProvider with an invalid property. Property {2} with value {3} was not of the expected type (String, String[], or Collection<String>) and will be ignored.
37
METADATA_PARSE_ERROR=Unable to parse metadata XML at {0} for bundle ID {1}.
(-)src/org/eclipse/equinox/metatype/impl/FragmentUtils.java (+58 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype.impl;
12
13
import java.net.URL;
14
import java.util.List;
15
import org.osgi.framework.Bundle;
16
import org.osgi.framework.wiring.BundleRevision;
17
import org.osgi.framework.wiring.BundleWiring;
18
19
/*
20
 * Fragment Utilities
21
 */
22
public class FragmentUtils {
23
24
	/*
25
	 * 
26
	 */
27
	public static boolean isFragment(Bundle bundle) {
28
		return (bundle.adapt(BundleRevision.class).getTypes() & BundleRevision.TYPE_FRAGMENT) != 0;
29
	}
30
31
	/*
32
	 * Find all the URLs to entries for the bundle and its fragments.
33
	 */
34
	public static URL[] findEntries(Bundle bundle, String path) {
35
		BundleWiring wiring = bundle.adapt(BundleWiring.class);
36
		if (wiring == null)
37
			return null;
38
		String directory = "/"; //$NON-NLS-1$
39
		String file = "*"; //$NON-NLS-1$
40
		int index = path.lastIndexOf(MetaTypeProviderImpl.DIRECTORY_SEP);
41
		switch (index) {
42
			case -1 :
43
				file = path;
44
				break;
45
			case 0 :
46
				if (path.length() > 1)
47
					file = path.substring(1);
48
				break;
49
			default :
50
				directory = path.substring(0, index);
51
				file = path.substring(index + 1);
52
		}
53
		List<URL> entries = wiring.findEntries(directory, file, 0);
54
		if (entries == null)
55
			return null;
56
		return entries.toArray(new URL[entries.size()]);
57
	}
58
}
(-)src/org/eclipse/equinox/metatype/impl/Icon.java (+72 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005 IBM Corporation.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype.impl;
12
13
import org.osgi.framework.Bundle;
14
15
/**
16
 * Represents an Icon with a name and a size
17
 */
18
class Icon implements Cloneable {
19
20
	private String _fileName;
21
	private int _size;
22
	private Bundle _bundle;
23
24
	/**
25
	 * Constructor of class Icon.
26
	 */
27
	public Icon(String fileName, int size, Bundle bundle) {
28
29
		this._fileName = fileName;
30
		this._size = size;
31
		this._bundle = bundle;
32
	}
33
34
	/**
35
	 * Constructor of class Icon.
36
	 */
37
	public Icon(String fileName, Bundle bundle) {
38
39
		// Integer.MIN_VALUE signifies size was not specified
40
		this(fileName, Integer.MIN_VALUE, bundle);
41
	}
42
43
	/*
44
	 * 
45
	 */
46
	public synchronized Object clone() {
47
		return new Icon(this._fileName, this._size, this._bundle);
48
	}
49
50
	/**
51
	 * Method to get the icon's file name.
52
	 */
53
	String getIconName() {
54
		return _fileName;
55
	}
56
57
	/**
58
	 * returns the size specified when the icon was created
59
	 * 
60
	 * @return size or Integer.MIN_VALUE if no size was specified
61
	 */
62
	int getIconSize() {
63
		return _size;
64
	}
65
66
	/**
67
	 * Method to get the bundle having this Icon.
68
	 */
69
	Bundle getIconBundle() {
70
		return _bundle;
71
	}
72
}
(-)src/org/eclipse/equinox/metatype/impl/LocalizationElement.java (+55 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype.impl;
12
13
import java.util.MissingResourceException;
14
import java.util.ResourceBundle;
15
16
public class LocalizationElement {
17
18
	public static final char KEY_SIGN = '%';
19
	String _localization = null;
20
	ResourceBundle _rb;
21
22
	/**
23
	 * Internal method
24
	 */
25
	void setResourceBundle(ResourceBundle rb) {
26
		this._rb = rb;
27
	}
28
29
	/**
30
	 * Method to get the localized text of inputed String.
31
	 */
32
	String getLocalized(String key) {
33
34
		if (key == null) {
35
			return null;
36
		}
37
38
		if ((key.length() > 1) && (key.charAt(0) == KEY_SIGN)) {
39
			if (_rb != null) {
40
				try {
41
					String transfered = _rb.getString(key.substring(1));
42
					if (transfered != null) {
43
						return transfered;
44
					}
45
				} catch (MissingResourceException mre) {
46
					// Nothing found for this key.
47
				}
48
			}
49
			// If no localization file available or no localized value found
50
			// for the key, then return the raw data without the key-sign.
51
			return key.substring(1);
52
		}
53
		return key;
54
	}
55
}
(-)src/org/eclipse/equinox/metatype/impl/LogMessages.properties (+17 lines)
Added Link Here
1
###############################################################################
2
# Copyright (c) 2005, 2010 IBM Corporation and others.
3
# All rights reserved. This program and the accompanying materials
4
# are made available under the terms of the Eclipse Public License v1.0
5
# which accompanies this distribution, and is available at
6
# http://www.eclipse.org/legal/epl-v10.html
7
#
8
# Contributors:
9
#     IBM Corporation - initial API and implementation
10
###############################################################################
11
# NLS_MESSAGEFORMAT_ALL 
12
13
Unknown_Log_level=Unknown Log Level
14
Info=Log Info
15
Warning=Log Warning
16
Error=Log Error
17
Debug=Log Debug
(-)src/org/eclipse/equinox/metatype/impl/LogTracker.java (+177 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 1998, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype.impl;
12
13
import java.io.PrintStream;
14
import java.util.Calendar;
15
import java.util.Date;
16
import org.osgi.framework.BundleContext;
17
import org.osgi.framework.ServiceReference;
18
import org.osgi.service.log.LogService;
19
import org.osgi.util.tracker.ServiceTracker;
20
21
/**
22
 * LogTracker class. This class encapsulates the LogService
23
 * and handles all issues such as the service coming and going.
24
 */
25
26
public class LogTracker extends ServiceTracker<LogService, LogService> implements LogService {
27
	/** LogService interface class name */
28
	protected final static String clazz = "org.osgi.service.log.LogService"; //$NON-NLS-1$
29
30
	/** PrintStream to use if LogService is unavailable */
31
	private final PrintStream out;
32
33
	/**
34
	 * Create new LogTracker.
35
	 *
36
	 * @param context BundleContext of parent bundle.
37
	 * @param out Default PrintStream to use if LogService is unavailable.
38
	 */
39
	public LogTracker(BundleContext context, PrintStream out) {
40
		super(context, clazz, null);
41
		this.out = out;
42
	}
43
44
	/*
45
	 * ----------------------------------------------------------------------
46
	 *      LogService Interface implementation
47
	 * ----------------------------------------------------------------------
48
	 */
49
50
	public void log(int level, String message) {
51
		log(null, level, message, null);
52
	}
53
54
	public void log(int level, String message, Throwable exception) {
55
		log(null, level, message, exception);
56
	}
57
58
	// Must suppress warnings here because the log service is not
59
	@SuppressWarnings("rawtypes")
60
	public void log(ServiceReference reference, int level, String message) {
61
		log(reference, level, message, null);
62
	}
63
64
	// Must suppress warnings here because the log service is not
65
	@SuppressWarnings("rawtypes")
66
	public synchronized void log(ServiceReference reference, int level, String message, Throwable exception) {
67
		ServiceReference<LogService>[] references = getServiceReferences();
68
69
		if (references != null) {
70
			int size = references.length;
71
72
			for (int i = 0; i < size; i++) {
73
				LogService service = getService(references[i]);
74
				if (service != null) {
75
					try {
76
						service.log(reference, level, message, exception);
77
					} catch (Exception e) {
78
						// TODO: consider printing to System Error
79
					}
80
				}
81
			}
82
83
			return;
84
		}
85
86
		noLogService(level, message, exception, reference);
87
	}
88
89
	/**
90
	 * The LogService is not available so we write the message to a PrintStream.
91
	 *
92
	 * @param level Logging level
93
	 * @param message Log message.
94
	 * @param throwable Log exception or null if none.
95
	 * @param reference ServiceReference associated with message or null if none.
96
	 */
97
	protected void noLogService(int level, String message, Throwable throwable, ServiceReference<?> reference) {
98
		if (out != null) {
99
			synchronized (out) {
100
				// Bug #113286.  If no log service present and messages are being
101
				// printed to stdout, prepend message with a timestamp.
102
				String timestamp = getDate(new Date());
103
				out.print(timestamp + " "); //$NON-NLS-1$
104
105
				switch (level) {
106
					case LOG_DEBUG : {
107
						out.print(LogTrackerMsg.Debug);
108
109
						break;
110
					}
111
					case LOG_INFO : {
112
						out.print(LogTrackerMsg.Info);
113
114
						break;
115
					}
116
					case LOG_WARNING : {
117
						out.print(LogTrackerMsg.Warning);
118
119
						break;
120
					}
121
					case LOG_ERROR : {
122
						out.print(LogTrackerMsg.Error);
123
124
						break;
125
					}
126
					default : {
127
						out.print("["); //$NON-NLS-1$
128
						out.print(LogTrackerMsg.Unknown_Log_level);
129
						out.print("]: "); //$NON-NLS-1$
130
131
						break;
132
					}
133
				}
134
135
				out.println(message);
136
137
				if (reference != null) {
138
					out.println(reference);
139
				}
140
141
				if (throwable != null) {
142
					throwable.printStackTrace(out);
143
				}
144
			}
145
		}
146
	}
147
148
	// from EclipseLog to avoid using DateFormat -- see bug 149892#c10
149
	private String getDate(Date date) {
150
		Calendar c = Calendar.getInstance();
151
		c.setTime(date);
152
		StringBuffer sb = new StringBuffer();
153
		appendPaddedInt(c.get(Calendar.YEAR), 4, sb).append('-');
154
		appendPaddedInt(c.get(Calendar.MONTH) + 1, 2, sb).append('-');
155
		appendPaddedInt(c.get(Calendar.DAY_OF_MONTH), 2, sb).append(' ');
156
		appendPaddedInt(c.get(Calendar.HOUR_OF_DAY), 2, sb).append(':');
157
		appendPaddedInt(c.get(Calendar.MINUTE), 2, sb).append(':');
158
		appendPaddedInt(c.get(Calendar.SECOND), 2, sb).append('.');
159
		appendPaddedInt(c.get(Calendar.MILLISECOND), 3, sb);
160
		return sb.toString();
161
	}
162
163
	private StringBuffer appendPaddedInt(int value, int pad, StringBuffer buffer) {
164
		pad = pad - 1;
165
		if (pad == 0)
166
			return buffer.append(Integer.toString(value));
167
		int padding = (int) Math.pow(10, pad);
168
		if (value >= padding)
169
			return buffer.append(Integer.toString(value));
170
		while (padding > value && padding > 1) {
171
			buffer.append('0');
172
			padding = padding / 10;
173
		}
174
		buffer.append(value);
175
		return buffer;
176
	}
177
}
(-)src/org/eclipse/equinox/metatype/impl/LogTrackerMsg.java (+28 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype.impl;
12
13
import org.eclipse.osgi.util.NLS;
14
15
public class LogTrackerMsg extends NLS {
16
	private static final String BUNDLE_NAME = "org.eclipse.equinox.metatype.LogMessages"; //$NON-NLS-1$
17
18
	public static String Unknown_Log_level;
19
	public static String Info;
20
	public static String Warning;
21
	public static String Error;
22
	public static String Debug;
23
24
	static {
25
		// initialize resource bundles
26
		NLS.initializeMessages(BUNDLE_NAME, LogTrackerMsg.class);
27
	}
28
}
(-)src/org/eclipse/equinox/metatype/impl/MetaTypeInformationImpl.java (+89 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype.impl;
12
13
import org.eclipse.equinox.metatype.EquinoxMetaTypeInformation;
14
15
import java.util.Enumeration;
16
import java.util.Vector;
17
import javax.xml.parsers.SAXParser;
18
import org.osgi.framework.Bundle;
19
import org.osgi.service.log.LogService;
20
21
/**
22
 * Implementation of MetaTypeProvider
23
 * <p>
24
 * Extension of MetaTypeProvider
25
 * <p>
26
 * Provides methods to:
27
 * <p> - getPids() get the Pids for a given Locale
28
 * <p> - getFactoryPids() get the Factory Pids for a given Locale
29
 * <p>
30
 */
31
public class MetaTypeInformationImpl extends MetaTypeProviderImpl implements EquinoxMetaTypeInformation {
32
33
	/**
34
	 * Constructor of class MetaTypeInformationImpl.
35
	 */
36
	MetaTypeInformationImpl(Bundle bundle, SAXParser parser, LogService logger) {
37
		super(bundle, parser, logger);
38
	}
39
40
	/*
41
	 * (non-Javadoc)
42
	 * 
43
	 * @see org.osgi.service.metatype.MetaTypeInformation#getPids()
44
	 */
45
	public String[] getPids() {
46
47
		if (_allPidOCDs.size() == 0) {
48
			return new String[0];
49
		}
50
51
		Vector<String> pids = new Vector<String>(7);
52
		Enumeration<String> e = _allPidOCDs.keys();
53
		while (e.hasMoreElements()) {
54
			pids.addElement(e.nextElement());
55
		}
56
57
		String[] retvalue = new String[pids.size()];
58
		pids.toArray(retvalue);
59
		return retvalue;
60
	}
61
62
	/*
63
	 * (non-Javadoc)
64
	 * 
65
	 * @see org.osgi.service.metatype.MetaTypeInformation#getFactoryPids()
66
	 */
67
	public String[] getFactoryPids() {
68
		if (_allFPidOCDs.size() == 0) {
69
			return new String[0];
70
		}
71
		Vector<String> fpids = new Vector<String>(7);
72
		Enumeration<String> e = _allFPidOCDs.keys();
73
		while (e.hasMoreElements()) {
74
			fpids.addElement(e.nextElement());
75
		}
76
		String[] retvalue = new String[fpids.size()];
77
		fpids.toArray(retvalue);
78
		return retvalue;
79
	}
80
81
	/*
82
	 * (non-Javadoc)
83
	 * 
84
	 * @see org.osgi.service.metatype.MetaTypeInformation#getBundle()
85
	 */
86
	public Bundle getBundle() {
87
		return this._bundle;
88
	}
89
}
(-)src/org/eclipse/equinox/metatype/impl/MetaTypeMsg.java (+46 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype.impl;
12
13
import org.eclipse.osgi.util.NLS;
14
15
public class MetaTypeMsg extends NLS {
16
	private static final String BUNDLE_NAME = "org.eclipse.equinox.metatype.ExternalMessages"; //$NON-NLS-1$
17
18
	public static String SERVICE_DESCRIPTION;
19
	public static String UNEXPECTED_ELEMENT;
20
	public static String UNEXPECTED_TEXT;
21
	public static String MISSING_ATTRIBUTE;
22
	public static String INVALID_TYPE;
23
	public static String MISSING_DESIGNATE_PID_AND_FACTORYPID;
24
	public static String OCD_ID_NOT_FOUND;
25
	public static String MISSING_ELEMENT;
26
	public static String EXCEPTION_MESSAGE;
27
	public static String NULL_IS_INVALID;
28
	public static String VALUE_OUT_OF_RANGE;
29
	public static String VALUE_OUT_OF_OPTION;
30
	public static String CARDINALITY_VIOLATION;
31
	public static String NULL_OPTIONS;
32
	public static String INCONSISTENT_OPTIONS;
33
	public static String INVALID_OPTIONS;
34
	public static String INVALID_DEFAULTS;
35
	public static String METADATA_NOT_FOUND;
36
	public static String ASK_INVALID_LOCALE;
37
	public static String MISSING_REQUIRED_PARAMETER;
38
	public static String TOKENIZER_GOT_INVALID_DATA;
39
	public static String INVALID_PID_METATYPE_PROVIDER_IGNORED;
40
	public static String METADATA_PARSE_ERROR;
41
42
	static {
43
		// initialize resource bundles
44
		NLS.initializeMessages(BUNDLE_NAME, MetaTypeMsg.class);
45
	}
46
}
(-)src/org/eclipse/equinox/metatype/impl/MetaTypeProviderImpl.java (+239 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype.impl;
12
13
import org.eclipse.equinox.metatype.EquinoxObjectClassDefinition;
14
15
import java.io.IOException;
16
import java.net.URL;
17
import java.util.*;
18
import javax.xml.parsers.SAXParser;
19
import org.eclipse.osgi.util.NLS;
20
import org.osgi.framework.Bundle;
21
import org.osgi.framework.Constants;
22
import org.osgi.framework.wiring.BundleWiring;
23
import org.osgi.service.log.LogService;
24
import org.osgi.service.metatype.MetaTypeProvider;
25
import org.osgi.service.metatype.MetaTypeService;
26
27
/**
28
 * Implementation of MetaTypeProvider
29
 */
30
public class MetaTypeProviderImpl implements MetaTypeProvider {
31
32
	public static final String METADATA_NOT_FOUND = "METADATA_NOT_FOUND"; //$NON-NLS-1$
33
	public static final String OCD_ID_NOT_FOUND = "OCD_ID_NOT_FOUND"; //$NON-NLS-1$
34
	public static final String ASK_INVALID_LOCALE = "ASK_INVALID_LOCALE"; //$NON-NLS-1$
35
36
	public static final String META_FILE_EXT = ".XML"; //$NON-NLS-1$
37
	public static final String RESOURCE_FILE_CONN = "_"; //$NON-NLS-1$
38
	public static final String RESOURCE_FILE_EXT = ".properties"; //$NON-NLS-1$
39
	public static final char DIRECTORY_SEP = '/';
40
41
	Bundle _bundle;
42
43
	Hashtable<String, ObjectClassDefinitionImpl> _allPidOCDs = new Hashtable<String, ObjectClassDefinitionImpl>(7);
44
	Hashtable<String, ObjectClassDefinitionImpl> _allFPidOCDs = new Hashtable<String, ObjectClassDefinitionImpl>(7);
45
46
	String[] _locales;
47
	boolean _isThereMeta = false;
48
49
	// Give access to subclasses.
50
	protected final LogService logger;
51
52
	/**
53
	 * Constructor of class MetaTypeProviderImpl.
54
	 */
55
	MetaTypeProviderImpl(Bundle bundle, SAXParser parser, LogService logger) {
56
57
		this._bundle = bundle;
58
		this.logger = logger;
59
60
		// read all bundle's metadata files and build internal data structures
61
		_isThereMeta = readMetaFiles(bundle, parser);
62
63
		if (!_isThereMeta) {
64
			logger.log(LogService.LOG_DEBUG, NLS.bind(MetaTypeMsg.METADATA_NOT_FOUND, new Long(bundle.getBundleId()), bundle.getSymbolicName()));
65
		}
66
	}
67
68
	/**
69
	 * This method should do the following:
70
	 * <p> - Obtain a SAX parser from the XML Parser Service:
71
	 * <p>
72
	 * 
73
	 * <pre>	</pre>
74
	 * 
75
	 * The parser may be SAX 1 (eXML) or SAX 2 (XML4J). It should attempt to use
76
	 * a SAX2 parser by instantiating an XMLReader and extending DefaultHandler
77
	 * BUT if that fails it should fall back to instantiating a SAX1 Parser and
78
	 * extending HandlerBase.
79
	 * <p> - Pass the parser the URL for the bundle's METADATA.XML file
80
	 * <p> - Handle the callbacks from the parser and build the appropriate
81
	 * MetaType objects - ObjectClassDefinitions & AttributeDefinitions
82
	 * 
83
	 * @param bundle The bundle object for which the metadata should be read
84
	 * @param parserFactory The bundle object for which the metadata should be
85
	 *        read
86
	 * @return void
87
	 * @throws IOException If there are errors accessing the metadata.xml file
88
	 */
89
	private boolean readMetaFiles(Bundle bundle, SAXParser saxParser) {
90
		BundleWiring wiring = bundle.adapt(BundleWiring.class);
91
		if (wiring == null)
92
			return false;
93
		List<URL> entries = wiring.findEntries(MetaTypeService.METATYPE_DOCUMENTS_LOCATION, "*", 0); //$NON-NLS-1$
94
		if (entries == null)
95
			return false;
96
		boolean result = false;
97
		for (URL entry : entries) {
98
			if (entry.getPath().endsWith("/")) //$NON-NLS-1$
99
				continue;
100
			DataParser parser = new DataParser(bundle, entry, saxParser, logger);
101
			try {
102
				Collection<Designate> designates = parser.doParse();
103
				if (!designates.isEmpty()) {
104
					result = true;
105
				}
106
				for (Designate designate : designates) {
107
					if (designate.isFactory()) {
108
						_allFPidOCDs.put(designate.getFactoryPid(), designate.getObjectClassDefinition());
109
					} else {
110
						_allPidOCDs.put(designate.getPid(), designate.getObjectClassDefinition());
111
					}
112
				}
113
			} catch (Exception e) {
114
				logger.log(LogService.LOG_ERROR, NLS.bind(MetaTypeMsg.METADATA_PARSE_ERROR, new Object[] {entry, bundle.getBundleId()}), e);
115
			}
116
		}
117
		return result;
118
	}
119
120
	/*
121
	 * (non-Javadoc)
122
	 * 
123
	 * @see org.osgi.service.metatype.MetaTypeProvider#getObjectClassDefinition(java.lang.String,
124
	 *      java.lang.String)
125
	 */
126
	public EquinoxObjectClassDefinition getObjectClassDefinition(String pid, String locale) {
127
128
		if (isInvalidLocale(locale)) {
129
			throw new IllegalArgumentException(NLS.bind(MetaTypeMsg.ASK_INVALID_LOCALE, pid, locale));
130
		}
131
132
		ObjectClassDefinitionImpl ocd;
133
		if (_allPidOCDs.containsKey(pid)) {
134
			ocd = (ObjectClassDefinitionImpl) (_allPidOCDs.get(pid)).clone();
135
			ocd.setResourceBundle(locale, _bundle);
136
			return ocd;
137
		} else if (_allFPidOCDs.containsKey(pid)) {
138
			ocd = (ObjectClassDefinitionImpl) (_allFPidOCDs.get(pid)).clone();
139
			ocd.setResourceBundle(locale, _bundle);
140
			return ocd;
141
		} else {
142
			throw new IllegalArgumentException(NLS.bind(MetaTypeMsg.OCD_ID_NOT_FOUND, pid));
143
		}
144
	}
145
146
	/**
147
	 * Internal Method - Check if the locale is invalid.
148
	 */
149
	public boolean isInvalidLocale(String locale) {
150
151
		// Just a simple and quick check here.
152
		if (locale == null || locale.length() == 0)
153
			return false;
154
155
		int idx_first = locale.indexOf(ObjectClassDefinitionImpl.LOCALE_SEP);
156
		int idx_second = locale.lastIndexOf(ObjectClassDefinitionImpl.LOCALE_SEP);
157
		if (idx_first == -1 && locale.length() == 2)
158
			// It is format of only language.
159
			return false;
160
		if ((idx_first == 2) && (idx_second == 5 || idx_second == 2))
161
			// It is format of language + "_" + country [ + "_" + variation ].
162
			return false;
163
		return true;
164
	}
165
166
	/*
167
	 * (non-Javadoc)
168
	 * 
169
	 * @see org.osgi.service.metatype.MetaTypeProvider#getLocales()
170
	 */
171
	public synchronized String[] getLocales() {
172
173
		if (_locales != null)
174
			return checkForDefault(_locales);
175
		BundleWiring wiring = _bundle.adapt(BundleWiring.class);
176
		if (wiring == null)
177
			return null;
178
		Vector<String> localizationFiles = new Vector<String>(7);
179
		// get all the localization resources for PIDS
180
		Enumeration<ObjectClassDefinitionImpl> ocds = _allPidOCDs.elements();
181
		while (ocds.hasMoreElements()) {
182
			ObjectClassDefinitionImpl ocd = ocds.nextElement();
183
			if (ocd._localization != null && !localizationFiles.contains(ocd._localization))
184
				localizationFiles.add(ocd._localization);
185
		}
186
		// get all the localization resources for FPIDS
187
		ocds = _allFPidOCDs.elements();
188
		while (ocds.hasMoreElements()) {
189
			ObjectClassDefinitionImpl ocd = ocds.nextElement();
190
			if (ocd._localization != null && !localizationFiles.contains(ocd._localization))
191
				localizationFiles.add(ocd._localization);
192
		}
193
		if (localizationFiles.size() == 0)
194
			localizationFiles.add(getBundleLocalization(_bundle));
195
		Vector<String> locales = new Vector<String>(7);
196
		Enumeration<String> eLocalizationFiles = localizationFiles.elements();
197
		while (eLocalizationFiles.hasMoreElements()) {
198
			String localizationFile = eLocalizationFiles.nextElement();
199
			int iSlash = localizationFile.lastIndexOf(DIRECTORY_SEP);
200
			String baseDir;
201
			String baseFileName;
202
			if (iSlash < 0) {
203
				baseDir = ""; //$NON-NLS-1$
204
			} else {
205
				baseDir = localizationFile.substring(0, iSlash);
206
			}
207
			baseFileName = '/' + localizationFile + RESOURCE_FILE_CONN;
208
			List<URL> entries = wiring.findEntries(baseDir, "*.properties", 0); //$NON-NLS-1$
209
			if (entries == null)
210
				continue;
211
			for (URL entry : entries) {
212
				String resource = entry.getPath();
213
				if (resource.startsWith(baseFileName) && resource.toLowerCase().endsWith(RESOURCE_FILE_EXT))
214
					locales.add(resource.substring(baseFileName.length(), resource.length() - RESOURCE_FILE_EXT.length()));
215
			}
216
		}
217
		_locales = locales.toArray(new String[locales.size()]);
218
		return checkForDefault(_locales);
219
	}
220
221
	static String getBundleLocalization(Bundle bundle) {
222
		// Use the Bundle-Localization manifest header value if it exists.
223
		String baseName = bundle.getHeaders("").get(Constants.BUNDLE_LOCALIZATION); //$NON-NLS-1$
224
		if (baseName == null)
225
			// If the manifest header does not exist, use the default.
226
			baseName = Constants.BUNDLE_LOCALIZATION_DEFAULT_BASENAME;
227
		return baseName;
228
	}
229
230
	/**
231
	 * Internal Method - checkForDefault
232
	 */
233
	private String[] checkForDefault(String[] locales) {
234
235
		if (locales == null || locales.length == 0 || (locales.length == 1 && Locale.getDefault().toString().equals(locales[0])))
236
			return null;
237
		return locales;
238
	}
239
}
(-)src/org/eclipse/equinox/metatype/impl/MetaTypeProviderTracker.java (+287 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype.impl;
12
13
import org.eclipse.equinox.metatype.*;
14
15
import java.io.IOException;
16
import java.io.InputStream;
17
import java.util.*;
18
import org.eclipse.osgi.util.NLS;
19
import org.osgi.framework.*;
20
import org.osgi.service.cm.ManagedService;
21
import org.osgi.service.cm.ManagedServiceFactory;
22
import org.osgi.service.log.LogService;
23
import org.osgi.service.metatype.*;
24
import org.osgi.util.tracker.ServiceTracker;
25
26
public class MetaTypeProviderTracker implements EquinoxMetaTypeInformation {
27
	private final Bundle _bundle;
28
	private final LogService log;
29
	private final ServiceTracker<Object, Object> _tracker;
30
31
	/**
32
	 * Constructs a MetaTypeProviderTracker which tracks all MetaTypeProviders
33
	 * registered by the specified bundle.
34
	 * @param context The BundleContext of the MetaTypeService implementation
35
	 * @param bundle The bundle to track all MetaTypeProviders for.
36
	 * @param log The {@code LogService} to use for logging messages.
37
	 */
38
	public MetaTypeProviderTracker(Bundle bundle, LogService log, ServiceTracker<Object, Object> tracker) {
39
		this._bundle = bundle;
40
		this._tracker = tracker;
41
		this.log = log;
42
	}
43
44
	private String[] getPids(boolean factory) {
45
		if (_bundle.getState() != Bundle.ACTIVE)
46
			return new String[0]; // return none if not active
47
		MetaTypeProviderWrapper[] wrappers = getMetaTypeProviders();
48
		ArrayList<String> results = new ArrayList<String>();
49
		for (int i = 0; i < wrappers.length; i++) {
50
			// return only the correct type of pids (regular or factory)
51
			if (factory == wrappers[i].factory)
52
				results.add(wrappers[i].pid);
53
		}
54
		return results.toArray(new String[results.size()]);
55
	}
56
57
	public String[] getPids() {
58
		return getPids(false);
59
	}
60
61
	public String[] getFactoryPids() {
62
		return getPids(true);
63
	}
64
65
	public Bundle getBundle() {
66
		return _bundle;
67
	}
68
69
	public EquinoxObjectClassDefinition getObjectClassDefinition(String id, String locale) {
70
		if (_bundle.getState() != Bundle.ACTIVE)
71
			return null; // return none if not active
72
		MetaTypeProviderWrapper[] wrappers = getMetaTypeProviders();
73
		for (int i = 0; i < wrappers.length; i++) {
74
			if (id.equals(wrappers[i].pid))
75
				// found a matching pid now call the actual provider
76
				return wrappers[i].getObjectClassDefinition(id, locale);
77
		}
78
		return null;
79
	}
80
81
	public String[] getLocales() {
82
		if (_bundle.getState() != Bundle.ACTIVE)
83
			return new String[0]; // return none if not active
84
		MetaTypeProviderWrapper[] wrappers = getMetaTypeProviders();
85
		ArrayList<String> locales = new ArrayList<String>();
86
		// collect all the unique locales from all providers we found
87
		for (int i = 0; i < wrappers.length; i++) {
88
			String[] wrappedLocales = wrappers[i].getLocales();
89
			if (wrappedLocales == null)
90
				continue;
91
			for (int j = 0; j < wrappedLocales.length; j++)
92
				if (!locales.contains(wrappedLocales[j]))
93
					locales.add(wrappedLocales[j]);
94
		}
95
		return locales.toArray(new String[locales.size()]);
96
	}
97
98
	private MetaTypeProviderWrapper[] getMetaTypeProviders() {
99
		Map<ServiceReference<Object>, Object> services = _tracker.getTracked();
100
		if (services.isEmpty())
101
			return new MetaTypeProviderWrapper[0];
102
		Set<ServiceReference<Object>> serviceReferences = services.keySet();
103
		Set<MetaTypeProviderWrapper> result = new HashSet<MetaTypeProviderWrapper>();
104
		for (ServiceReference<Object> serviceReference : serviceReferences) {
105
			if (serviceReference.getBundle() == _bundle) {
106
				Object service = services.get(serviceReference);
107
				// If the service is not a MetaTypeProvider, we're not interested in it.
108
				if (service instanceof MetaTypeProvider) {
109
					// Include the METATYPE_PID, if present, to return as part of getPids(). Also, include the 
110
					// METATYPE_FACTORY_PID, if present, to return as part of getFactoryPids().
111
					// The filter ensures at least one of these properties was set for a standalone MetaTypeProvider.
112
					addMetaTypeProviderWrappers(MetaTypeProvider.METATYPE_PID, serviceReference, (MetaTypeProvider) service, false, result);
113
					addMetaTypeProviderWrappers(MetaTypeProvider.METATYPE_FACTORY_PID, serviceReference, (MetaTypeProvider) service, true, result);
114
					// If the service is a ManagedService, include the SERVICE_PID to return as part of getPids().
115
					// The filter ensures the SERVICE_PID property was set.
116
					if (service instanceof ManagedService) {
117
						addMetaTypeProviderWrappers(Constants.SERVICE_PID, serviceReference, (MetaTypeProvider) service, false, result);
118
					}
119
					// If the service is a ManagedServiceFactory, include the SERVICE_PID to return as part of getFactoryPids().
120
					// The filter ensures the SERVICE_PID property was set.
121
					else if (service instanceof ManagedServiceFactory) {
122
						addMetaTypeProviderWrappers(Constants.SERVICE_PID, serviceReference, (MetaTypeProvider) service, true, result);
123
					}
124
				}
125
			}
126
		}
127
		return result.toArray(new MetaTypeProviderWrapper[result.size()]);
128
	}
129
130
	private void addMetaTypeProviderWrappers(String servicePropertyName, ServiceReference<Object> serviceReference, MetaTypeProvider service, boolean factory, Set<MetaTypeProviderWrapper> wrappers) {
131
		String[] pids = getStringProperty(servicePropertyName, serviceReference.getProperty(servicePropertyName));
132
		for (String pid : pids) {
133
			wrappers.add(new MetaTypeProviderWrapper(service, pid, factory));
134
		}
135
	}
136
137
	private String[] getStringProperty(String name, Object value) {
138
		// Don't log a warning if the value is null. The filter guarantees at least one of the necessary properties
139
		// is there. If others are not, this method will get called with value equal to null.
140
		if (value == null)
141
			return new String[0];
142
		if (value instanceof String) {
143
			return new String[] {(String) value};
144
		}
145
		if (value instanceof String[]) {
146
			return (String[]) value;
147
		}
148
		Exception e = null;
149
		if (value instanceof Collection) {
150
			@SuppressWarnings("unchecked")
151
			Collection<String> temp = (Collection<String>) value;
152
			try {
153
				return temp.toArray(new String[temp.size()]);
154
			} catch (ArrayStoreException ase) {
155
				e = ase;
156
			}
157
		}
158
		log.log(LogService.LOG_WARNING, NLS.bind(MetaTypeMsg.INVALID_PID_METATYPE_PROVIDER_IGNORED, new Object[] {_bundle.getSymbolicName(), _bundle.getBundleId(), name, value}), e);
159
		return new String[0];
160
	}
161
162
	// this is a simple class just used to temporarily store information about a provider
163
	public class MetaTypeProviderWrapper implements MetaTypeProvider {
164
		private final MetaTypeProvider provider;
165
		final String pid;
166
		final boolean factory;
167
168
		MetaTypeProviderWrapper(MetaTypeProvider provider, String pid, boolean factory) {
169
			this.provider = provider;
170
			this.pid = pid;
171
			this.factory = factory;
172
		}
173
174
		@Override
175
		public boolean equals(Object object) {
176
			if (object == this)
177
				return true;
178
			if (!(object instanceof MetaTypeProviderWrapper))
179
				return false;
180
			MetaTypeProviderWrapper that = (MetaTypeProviderWrapper) object;
181
			return this.provider.equals(that.provider) && this.pid.equals(that.pid) && this.factory == that.factory;
182
		}
183
184
		@Override
185
		public int hashCode() {
186
			int result = 17;
187
			result = 31 * result + provider.hashCode();
188
			result = 31 * result + pid.hashCode();
189
			result = 31 * result + (factory ? 1 : 0);
190
			return result;
191
		}
192
193
		public EquinoxObjectClassDefinition getObjectClassDefinition(String id, String locale) {
194
			final ObjectClassDefinition ocd = provider.getObjectClassDefinition(id, locale);
195
			if (ocd == null)
196
				return null;
197
			return new EquinoxObjectClassDefinition() {
198
				public String getName() {
199
					return ocd.getName();
200
				}
201
202
				public String getID() {
203
					return ocd.getID();
204
				}
205
206
				public String getDescription() {
207
					return ocd.getDescription();
208
				}
209
210
				public InputStream getIcon(int size) throws IOException {
211
					return ocd.getIcon(size);
212
				}
213
214
				@SuppressWarnings("unchecked")
215
				public Map<String, String> getExtensionAttributes(String schema) {
216
					return Collections.EMPTY_MAP;
217
				}
218
219
				@SuppressWarnings("unchecked")
220
				public Set<String> getExtensionUris() {
221
					return Collections.EMPTY_SET;
222
				}
223
224
				public EquinoxAttributeDefinition[] getAttributeDefinitions(int filter) {
225
					AttributeDefinition[] ads = ocd.getAttributeDefinitions(filter);
226
					if (ads == null || ads.length == 0)
227
						return new EquinoxAttributeDefinition[0];
228
					Collection<EquinoxAttributeDefinition> result = new ArrayList<EquinoxAttributeDefinition>(ads.length);
229
					for (final AttributeDefinition ad : ads) {
230
						result.add(new EquinoxAttributeDefinition() {
231
							public String getName() {
232
								return ad.getName();
233
							}
234
235
							public String getID() {
236
								return ad.getID();
237
							}
238
239
							public String getDescription() {
240
								return ad.getDescription();
241
							}
242
243
							public int getCardinality() {
244
								return ad.getCardinality();
245
							}
246
247
							public int getType() {
248
								return ad.getType();
249
							}
250
251
							public String[] getOptionValues() {
252
								return ad.getOptionValues();
253
							}
254
255
							public String[] getOptionLabels() {
256
								return ad.getOptionLabels();
257
							}
258
259
							public String validate(String value) {
260
								return ad.validate(value);
261
							}
262
263
							public String[] getDefaultValue() {
264
								return ad.getDefaultValue();
265
							}
266
267
							@SuppressWarnings("unchecked")
268
							public Map<String, String> getExtensionAttributes(String schema) {
269
								return Collections.EMPTY_MAP;
270
							}
271
272
							@SuppressWarnings("unchecked")
273
							public Set<String> getExtensionUris() {
274
								return Collections.EMPTY_SET;
275
							}
276
						});
277
					}
278
					return result.toArray(new EquinoxAttributeDefinition[result.size()]);
279
				}
280
			};
281
		}
282
283
		public String[] getLocales() {
284
			return provider.getLocales();
285
		}
286
	}
287
}
(-)src/org/eclipse/equinox/metatype/impl/MetaTypeServiceImpl.java (+137 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype.impl;
12
13
import org.eclipse.equinox.metatype.EquinoxMetaTypeInformation;
14
import org.eclipse.equinox.metatype.EquinoxMetaTypeService;
15
16
import java.security.AccessController;
17
import java.security.PrivilegedExceptionAction;
18
import java.util.Hashtable;
19
import javax.xml.parsers.*;
20
import org.eclipse.osgi.util.NLS;
21
import org.osgi.framework.*;
22
import org.osgi.service.log.LogService;
23
import org.osgi.util.tracker.ServiceTracker;
24
import org.xml.sax.SAXException;
25
26
/**
27
 * Implementation of MetaTypeService
28
 */
29
public class MetaTypeServiceImpl implements EquinoxMetaTypeService, SynchronousBundleListener {
30
31
	SAXParserFactory _parserFactory;
32
	private Hashtable<Long, EquinoxMetaTypeInformation> _mtps = new Hashtable<Long, EquinoxMetaTypeInformation>(7);
33
34
	private final LogService logger;
35
	private final ServiceTracker<Object, Object> metaTypeProviderTracker;
36
37
	/**
38
	 * Constructor of class MetaTypeServiceImpl.
39
	 */
40
	public MetaTypeServiceImpl(SAXParserFactory parserFactory, LogService logger, ServiceTracker<Object, Object> metaTypeProviderTracker) {
41
		this._parserFactory = parserFactory;
42
		this.logger = logger;
43
		this.metaTypeProviderTracker = metaTypeProviderTracker;
44
	}
45
46
	/*
47
	 * (non-Javadoc)
48
	 * 
49
	 * @see org.osgi.service.metatype.MetaTypeService#getMetaTypeInformation(org.osgi.framework.Bundle)
50
	 */
51
	public EquinoxMetaTypeInformation getMetaTypeInformation(Bundle bundle) {
52
		return getMetaTypeProvider(bundle);
53
	}
54
55
	/**
56
	 * Internal Method - to get MetaTypeProvider object.
57
	 */
58
	private EquinoxMetaTypeInformation getMetaTypeProvider(final Bundle b) {
59
		final LogService loggerTemp = this.logger;
60
		final ServiceTracker<Object, Object> tracker = this.metaTypeProviderTracker;
61
		try {
62
			Long bID = new Long(b.getBundleId());
63
			synchronized (_mtps) {
64
				if (_mtps.containsKey(bID))
65
					return _mtps.get(bID);
66
				// Avoid synthetic accessor method warnings.
67
68
				EquinoxMetaTypeInformation mti = AccessController.doPrivileged(new PrivilegedExceptionAction<EquinoxMetaTypeInformation>() {
69
					public EquinoxMetaTypeInformation run() throws ParserConfigurationException, SAXException {
70
						MetaTypeInformationImpl impl = new MetaTypeInformationImpl(b, newParser(), loggerTemp);
71
						if (!impl._isThereMeta)
72
							return new MetaTypeProviderTracker(b, loggerTemp, tracker);
73
						return impl;
74
					}
75
				});
76
				_mtps.put(bID, mti);
77
				return mti;
78
			}
79
		} catch (Exception e) {
80
			logger.log(LogService.LOG_ERROR, NLS.bind(MetaTypeMsg.EXCEPTION_MESSAGE, e.getMessage()), e);
81
			return new MetaTypeProviderTracker(b, loggerTemp, tracker);
82
		}
83
	}
84
85
	SAXParser newParser() throws ParserConfigurationException, SAXException {
86
		boolean namespaceAware = _parserFactory.isNamespaceAware();
87
		boolean validating = _parserFactory.isValidating();
88
		// Always want a non-validating parser.
89
		_parserFactory.setValidating(false);
90
		try {
91
			// If the factory is already namespace aware, we know it can create namespace aware parsers
92
			// because that was checked in the service tracker.
93
			if (namespaceAware) {
94
				return _parserFactory.newSAXParser();
95
			}
96
			// If the factory is not already namespace aware, it may or may not be able to create
97
			// namespace aware parsers.
98
			_parserFactory.setNamespaceAware(true);
99
			try {
100
				return _parserFactory.newSAXParser();
101
			} catch (Exception e) {
102
				// Factory cannot create namespace aware parsers. Go with the last resort.
103
				_parserFactory.setNamespaceAware(false);
104
				return _parserFactory.newSAXParser();
105
			}
106
		} finally {
107
			// Restore the previous settings in all cases.
108
			_parserFactory.setNamespaceAware(namespaceAware);
109
			_parserFactory.setValidating(validating);
110
		}
111
	}
112
113
	/*
114
	 * (non-Javadoc)
115
	 * 
116
	 * @see org.osgi.framework.BundleListener#bundleChanged(org.osgi.framework.BundleEvent)
117
	 */
118
	public void bundleChanged(BundleEvent event) {
119
120
		int type = event.getType();
121
		Long bID = new Long(event.getBundle().getBundleId());
122
123
		switch (type) {
124
			case BundleEvent.UPDATED :
125
			case BundleEvent.UNINSTALLED :
126
				_mtps.remove(bID);
127
				break;
128
			case BundleEvent.INSTALLED :
129
			case BundleEvent.RESOLVED :
130
			case BundleEvent.STARTED :
131
			case BundleEvent.STOPPED :
132
			case BundleEvent.UNRESOLVED :
133
			default :
134
				break;
135
		}
136
	}
137
}
(-)src/org/eclipse/equinox/metatype/impl/ObjectClassDefinitionImpl.java (+320 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype.impl;
12
13
import org.eclipse.equinox.metatype.EquinoxAttributeDefinition;
14
import org.eclipse.equinox.metatype.EquinoxObjectClassDefinition;
15
16
import java.io.IOException;
17
import java.io.InputStream;
18
import java.net.URL;
19
import java.util.*;
20
import org.osgi.framework.Bundle;
21
22
/**
23
 * Implementation of ObjectClassDefinition
24
 */
25
public class ObjectClassDefinitionImpl extends LocalizationElement implements EquinoxObjectClassDefinition, Cloneable {
26
27
	public static final char LOCALE_SEP = '_';
28
29
	String _name;
30
	String _id;
31
	String _description;
32
33
	int _type;
34
	Vector<AttributeDefinitionImpl> _required = new Vector<AttributeDefinitionImpl>(7);
35
	Vector<AttributeDefinitionImpl> _optional = new Vector<AttributeDefinitionImpl>(7);
36
	Icon _icon;
37
38
	private final ExtendableHelper helper;
39
40
	/*
41
	 * Constructor of class ObjectClassDefinitionImpl.
42
	 */
43
	public ObjectClassDefinitionImpl(String name, String description, String id, String localization, Map<String, Map<String, String>> extensionAttributes) {
44
		this(name, description, id, 0, localization, new ExtendableHelper(extensionAttributes));
45
	}
46
47
	/*
48
	 * Constructor of class ObjectClassDefinitionImpl.
49
	 */
50
	public ObjectClassDefinitionImpl(String name, String description, String id, int type, String localization, ExtendableHelper helper) {
51
		this._name = name;
52
		this._id = id;
53
		this._description = description;
54
		this._type = type;
55
		this._localization = localization;
56
		this.helper = helper;
57
	}
58
59
	/*
60
	 * 
61
	 */
62
	public synchronized Object clone() {
63
64
		ObjectClassDefinitionImpl ocd = new ObjectClassDefinitionImpl(_name, _description, _id, _type, _localization, helper);
65
		for (int i = 0; i < _required.size(); i++) {
66
			AttributeDefinitionImpl ad = _required.elementAt(i);
67
			ocd.addAttributeDefinition((AttributeDefinitionImpl) ad.clone(), true);
68
		}
69
		for (int i = 0; i < _optional.size(); i++) {
70
			AttributeDefinitionImpl ad = _optional.elementAt(i);
71
			ocd.addAttributeDefinition((AttributeDefinitionImpl) ad.clone(), false);
72
		}
73
		if (_icon != null) {
74
			ocd.setIcon((Icon) _icon.clone());
75
		}
76
		return ocd;
77
	}
78
79
	/*
80
	 * (non-Javadoc)
81
	 * 
82
	 * @see org.osgi.service.metatype.ObjectClassDefinition#getName()
83
	 */
84
	public String getName() {
85
		return getLocalized(_name);
86
	}
87
88
	/**
89
	 * Method to set the name of ObjectClassDefinition.
90
	 */
91
	void setName(String name) {
92
		this._name = name;
93
	}
94
95
	/*
96
	 * (non-Javadoc)
97
	 * 
98
	 * @see org.osgi.service.metatype.ObjectClassDefinition#getID()
99
	 */
100
	public String getID() {
101
		return _id;
102
	}
103
104
	/*
105
	 * (non-Javadoc)
106
	 * 
107
	 * @see org.osgi.service.metatype.ObjectClassDefinition#getDescription()
108
	 */
109
	public String getDescription() {
110
		return getLocalized(_description);
111
	}
112
113
	/*
114
	 * Method to set the description of ObjectClassDefinition.
115
	 */
116
	void setDescription(String description) {
117
		this._description = description;
118
	}
119
120
	/*
121
	 * (non-Javadoc)
122
	 * 
123
	 * @see org.osgi.service.metatype.ObjectClassDefinition#getAttributeDefinitions(int)
124
	 */
125
	public EquinoxAttributeDefinition[] getAttributeDefinitions(int filter) {
126
127
		EquinoxAttributeDefinition[] atts;
128
		switch (filter) {
129
			case REQUIRED :
130
				atts = new EquinoxAttributeDefinition[_required.size()];
131
				_required.toArray(atts);
132
				return atts;
133
			case OPTIONAL :
134
				atts = new EquinoxAttributeDefinition[_optional.size()];
135
				_optional.toArray(atts);
136
				return atts;
137
			case ALL :
138
			default :
139
				atts = new EquinoxAttributeDefinition[_required.size() + _optional.size()];
140
				Enumeration<AttributeDefinitionImpl> e = _required.elements();
141
				int i = 0;
142
				while (e.hasMoreElements()) {
143
					atts[i] = e.nextElement();
144
					i++;
145
				}
146
				e = _optional.elements();
147
				while (e.hasMoreElements()) {
148
					atts[i] = e.nextElement();
149
					i++;
150
				}
151
				return atts;
152
		}
153
	}
154
155
	/*
156
	 * Method to add one new AD to ObjectClassDefinition.
157
	 */
158
	void addAttributeDefinition(AttributeDefinitionImpl ad, boolean isRequired) {
159
160
		if (isRequired) {
161
			_required.addElement(ad);
162
		} else {
163
			_optional.addElement(ad);
164
		}
165
	}
166
167
	/*
168
	 * (non-Javadoc)
169
	 * 
170
	 * @see org.osgi.service.metatype.ObjectClassDefinition#getIcon(int)
171
	 */
172
	public InputStream getIcon(int sizeHint) throws IOException {
173
		// The parameter simply represents a requested size. This method should never return null if an
174
		// icon exists.
175
		// TODO This method may change further depending on the outcome of certain ongoing CPEG discussions.
176
		// It is thought that users should be able to specify the same icon multiple times but of different
177
		// sizes. This would require a change to the XML schema. This method would then return the icon with
178
		// a size closest to the requested size.
179
		if ((_icon == null)) {
180
			return null;
181
		}
182
		Bundle b = _icon.getIconBundle();
183
		URL[] urls = FragmentUtils.findEntries(b, getLocalized(_icon.getIconName()));
184
		if (urls != null && urls.length > 0) {
185
			return urls[0].openStream();
186
		}
187
		return null;
188
	}
189
190
	/**
191
	 * Method to set the icon of ObjectClassDefinition.
192
	 */
193
	void setIcon(Icon icon) {
194
		this._icon = icon;
195
	}
196
197
	/**
198
	 * Method to set the resource bundle for this OCD and all its ADs.
199
	 */
200
	void setResourceBundle(String assignedLocale, Bundle bundle) {
201
202
		_rb = getResourceBundle(assignedLocale, bundle);
203
204
		Enumeration<AttributeDefinitionImpl> allADReqs = _required.elements();
205
		while (allADReqs.hasMoreElements()) {
206
			AttributeDefinitionImpl ad = allADReqs.nextElement();
207
			ad.setResourceBundle(_rb);
208
		}
209
210
		Enumeration<AttributeDefinitionImpl> allADOpts = _optional.elements();
211
		while (allADOpts.hasMoreElements()) {
212
			AttributeDefinitionImpl ad = allADOpts.nextElement();
213
			ad.setResourceBundle(_rb);
214
		}
215
	}
216
217
	/*
218
	 * Internal Method - to get resource bundle.
219
	 */
220
	private ResourceBundle getResourceBundle(String locale, final Bundle bundle) {
221
		// Determine the base name of the bundle localization property files.
222
		// If the <MetaData> 'localization' attribute was not specified,
223
		// use the Bundle-Localization manifest header value instead if it exists.
224
		String resourceBase = _localization != null ? _localization : MetaTypeProviderImpl.getBundleLocalization(bundle);
225
226
		// There are seven searching candidates possible:
227
		// baseName + 
228
		//		"_" + language1 + "_" + country1 + "_" + variation1	+ ".properties"
229
		// or	"_" + language1 + "_" + country1					+ ".properties"
230
		// or	"_" + language1										+ ".properties"
231
		// or	"_" + language2 + "_" + country2 + "_" + variation2	+ ".properties"
232
		// or	"_" + language2 + "_" + country2					+ ".properties"
233
		// or	"_" + language2										+ ".properties"
234
		// or	""													+ ".properties"
235
		//
236
		// Where language1[_country1[_variation1]] is the requested locale,
237
		// and language2[_country2[_variation2]] is the default locale.
238
239
		String[] searchCandidates = new String[7];
240
241
		// Candidates from passed locale:
242
		if (locale != null && locale.length() > 0) {
243
			int idx1_first = locale.indexOf(LOCALE_SEP);
244
			if (idx1_first == -1) {
245
				// locale has only language.
246
				searchCandidates[2] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + locale;
247
			} else {
248
				// locale has at least language and country.
249
				searchCandidates[2] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + locale.substring(0, idx1_first);
250
				int idx1_second = locale.indexOf(LOCALE_SEP, idx1_first + 1);
251
				if (idx1_second == -1) {
252
					// locale just has both language and country.
253
					searchCandidates[1] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + locale;
254
				} else {
255
					// locale has language, country, and variation all.
256
					searchCandidates[1] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + locale.substring(0, idx1_second);
257
					searchCandidates[0] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + locale;
258
				}
259
			}
260
		}
261
262
		// Candidates from Locale.getDefault():
263
		String defaultLocale = Locale.getDefault().toString();
264
		int idx2_first = defaultLocale.indexOf(LOCALE_SEP);
265
		int idx2_second = defaultLocale.indexOf(LOCALE_SEP, idx2_first + 1);
266
		if (idx2_second != -1) {
267
			// default-locale is format of [language]_[country]_variation.
268
			searchCandidates[3] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + defaultLocale;
269
			if (searchCandidates[3].equalsIgnoreCase(searchCandidates[0])) {
270
				searchCandidates[3] = null;
271
			}
272
		}
273
		if ((idx2_first != -1) && (idx2_second != idx2_first + 1)) {
274
			// default-locale is format of [language]_country[_variation].
275
			searchCandidates[4] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + ((idx2_second == -1) ? defaultLocale : defaultLocale.substring(0, idx2_second));
276
			if (searchCandidates[4].equalsIgnoreCase(searchCandidates[1])) {
277
				searchCandidates[4] = null;
278
			}
279
		}
280
		if ((idx2_first == -1) && (defaultLocale.length() > 0)) {
281
			// default-locale has only language.
282
			searchCandidates[5] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + defaultLocale;
283
		} else if (idx2_first > 0) {
284
			// default-locale is format of language_[...].
285
			searchCandidates[5] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + defaultLocale.substring(0, idx2_first);
286
		}
287
		if (searchCandidates[5] != null && searchCandidates[5].equalsIgnoreCase(searchCandidates[2])) {
288
			searchCandidates[5] = null;
289
		}
290
291
		// The final candidate.
292
		searchCandidates[6] = ""; //$NON-NLS-1$
293
294
		URL resourceUrl = null;
295
		URL[] urls = null;
296
297
		for (int idx = 0; (idx < searchCandidates.length) && (resourceUrl == null); idx++) {
298
			urls = (searchCandidates[idx] == null ? null : FragmentUtils.findEntries(bundle, resourceBase + searchCandidates[idx] + MetaTypeProviderImpl.RESOURCE_FILE_EXT));
299
			if (urls != null && urls.length > 0)
300
				resourceUrl = urls[0];
301
		}
302
303
		if (resourceUrl != null) {
304
			try {
305
				return new PropertyResourceBundle(resourceUrl.openStream());
306
			} catch (IOException ioe) {
307
				// Exception when creating PropertyResourceBundle object.
308
			}
309
		}
310
		return null;
311
	}
312
313
	public Map<String, String> getExtensionAttributes(String schema) {
314
		return helper.getExtensionAttributes(schema);
315
	}
316
317
	public Set<String> getExtensionUris() {
318
		return helper.getExtensionUris();
319
	}
320
}
(-)src/org/eclipse/equinox/metatype/impl/ValueTokenizer.java (+274 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.metatype.impl;
12
13
import java.math.BigDecimal;
14
import java.math.BigInteger;
15
import java.util.*;
16
import org.eclipse.osgi.util.NLS;
17
import org.osgi.service.log.LogService;
18
import org.osgi.service.metatype.AttributeDefinition;
19
20
public class ValueTokenizer {
21
	private static final char DELIMITER = ',';
22
	private static final char ESCAPE = '\\';
23
24
	private final LogService logger;
25
	private final List<String> values = new ArrayList<String>();
26
27
	/*
28
	 * Constructor of class ValueTokenizer
29
	 */
30
	public ValueTokenizer(String values_str, LogService logger) {
31
		this.logger = logger;
32
		if (values_str == null)
33
			return;
34
		// The trick is to strip out unescaped whitespace characters before and
35
		// after the input string as well as before and after each 
36
		// individual token within the input string without losing any escaped 
37
		// whitespace characters. Whitespace between two non-whitespace
38
		// characters may or may not be escaped. Also, any character may be
39
		// escaped. The escape character is '\'. The delimiter is ','.
40
		StringBuffer buffer = new StringBuffer();
41
		// Loop over the characters within the input string and extract each
42
		// value token.
43
		for (int i = 0; i < values_str.length(); i++) {
44
			char c1 = values_str.charAt(i);
45
			switch (c1) {
46
				case DELIMITER :
47
					// When the delimiter is encountered, add the extracted 
48
					// token to the result and prepare the buffer to receive the
49
					// next token.
50
					values.add(buffer.toString());
51
					buffer.delete(0, buffer.length());
52
					break;
53
				case ESCAPE :
54
					// When the escape is encountered, add the immediately
55
					// following character to the token, unless the end of the
56
					// input has been reached. Note this will result in loop 
57
					// counter 'i' being incremented twice, once here and once 
58
					// at the end of the loop.
59
					if (i + 1 < values_str.length()) {
60
						buffer.append(values_str.charAt(++i));
61
					} else {
62
						// If the ESCAPE character occurs as the last character
63
						// of the string, log the error and ignore it.
64
						logger.log(LogService.LOG_ERROR, "ValueTokenizer.ValueTokenizer(String) " + MetaTypeMsg.TOKENIZER_GOT_INVALID_DATA); //$NON-NLS-1$
65
					}
66
					break;
67
				default :
68
					// For all other characters, add them to the current token
69
					// unless dealing with unescaped whitespace at the beginning
70
					// or end. We know the whitespace is unescaped because it
71
					// would have been handled in the ESCAPE case otherwise.
72
					if (Character.isWhitespace(c1)) {
73
						// Ignore unescaped whitespace at the beginning of the
74
						// token.
75
						if (buffer.length() == 0) {
76
							continue;
77
						}
78
						// If the whitespace is not at the beginning, look
79
						// forward, starting with the next character, to see if 
80
						// it's in the middle or at the end. Unescaped 
81
						// whitespace in the middle is okay.
82
						for (int j = i + 1; j < values_str.length(); j++) {
83
							// Keep looping until the end of the string is
84
							// reached or a non-whitespace character other than
85
							// the escape is seen.
86
							char c2 = values_str.charAt(j);
87
							if (!Character.isWhitespace(c2)) {
88
								// If the current character is not the DELIMITER, all whitespace 
89
								// characters are significant and should be added to the token.
90
								// Otherwise, they're at the end and should be ignored. But watch
91
								// out for an escape character at the end of the input. Ignore it
92
								// and any previous insignificant whitespace if it exists.
93
								if (c2 == ESCAPE && j + 1 >= values_str.length()) {
94
									continue;
95
								}
96
								if (c2 != DELIMITER) {
97
									buffer.append(values_str.substring(i, j));
98
								}
99
								// Let loop counter i catch up with the inner loop but keep in
100
								// mind it will still be incremented at the end of the outer loop.
101
								i = j - 1;
102
								break;
103
							}
104
						}
105
					} else {
106
						// For non-whitespace characters.
107
						buffer.append(c1);
108
					}
109
			}
110
		}
111
		// Don't forget to add the last token.
112
		values.add(buffer.toString());
113
	}
114
115
	/*
116
	 * Method to return values as Vector.
117
	 */
118
	public Collection<String> getValues() {
119
		return Collections.unmodifiableList(values);
120
	}
121
122
	/*
123
	 * Method to return values as String[] or null.
124
	 */
125
	public String[] getValuesAsArray() {
126
		if (values.isEmpty()) {
127
			return null;
128
		}
129
		return values.toArray(new String[values.size()]);
130
	}
131
132
	public String getValuesAsString() {
133
		if (values.isEmpty()) {
134
			return null;
135
		}
136
		if (values.size() == 1) {
137
			return values.get(0);
138
		}
139
		StringBuffer buffer = new StringBuffer(values.get(0));
140
		for (int i = 1; i < values.size(); i++) {
141
			buffer.append(',');
142
			buffer.append(values.get(i));
143
		}
144
		return buffer.toString();
145
	}
146
147
	public String validate(AttributeDefinitionImpl ad) {
148
		// An empty list means the original value was null. Null is never valid.
149
		if (values.isEmpty()) {
150
			return MetaTypeMsg.NULL_IS_INVALID;
151
		}
152
		try {
153
			// A value must match the cardinality.
154
			int cardinality = Math.abs(ad.getCardinality());
155
			// If the cardinality is zero, the value must contain one and only one token.
156
			if (cardinality == 0) {
157
				if (values.size() != 1) {
158
					return NLS.bind(MetaTypeMsg.CARDINALITY_VIOLATION, new Object[] {getValuesAsString(), values.size(), 1, 1});
159
				}
160
			}
161
			// Otherwise, the number of tokens must be between 0 and cardinality, inclusive.
162
			else if (values.size() > cardinality) {
163
				return NLS.bind(MetaTypeMsg.CARDINALITY_VIOLATION, new Object[] {getValuesAsString(), values.size(), 0, cardinality});
164
			}
165
			// Now inspect each token.
166
			for (Iterator<String> i = values.iterator(); i.hasNext();) {
167
				String s = i.next();
168
				// If options were declared and the value does not match one of them, the value is not valid.
169
				if (!ad._values.isEmpty() && !ad._values.contains(s)) {
170
					return NLS.bind(MetaTypeMsg.VALUE_OUT_OF_OPTION, s);
171
				}
172
				// Check the type. Also check the range if min or max were declared.
173
				boolean rangeError = false;
174
				switch (ad._dataType) {
175
					case AttributeDefinition.PASSWORD :
176
					case AttributeDefinition.STRING :
177
						if (ad._minValue != null && s.length() < (Integer) ad._minValue) {
178
							rangeError = true;
179
						} else if (ad._maxValue != null && s.length() > (Integer) ad._maxValue) {
180
							rangeError = true;
181
						}
182
						break;
183
					case AttributeDefinition.INTEGER :
184
						Integer intVal = new Integer(s);
185
						if (ad._minValue != null && intVal.compareTo((Integer) ad._minValue) < 0) {
186
							rangeError = true;
187
						} else if (ad._maxValue != null && intVal.compareTo((Integer) ad._maxValue) > 0) {
188
							rangeError = true;
189
						}
190
						break;
191
					case AttributeDefinition.LONG :
192
						Long longVal = new Long(s);
193
						if (ad._minValue != null && longVal.compareTo((Long) ad._minValue) < 0) {
194
							rangeError = true;
195
						} else if (ad._maxValue != null && longVal.compareTo((Long) ad._maxValue) > 0) {
196
							rangeError = true;
197
						}
198
						break;
199
					case AttributeDefinition.DOUBLE :
200
						Double doubleVal = new Double(s);
201
						if (ad._minValue != null && doubleVal.compareTo((Double) ad._minValue) < 0) {
202
							rangeError = true;
203
						} else if (ad._maxValue != null && doubleVal.compareTo((Double) ad._maxValue) > 0) {
204
							rangeError = true;
205
						}
206
						break;
207
					case AttributeDefinition.BOOLEAN :
208
						// Any string can be converted into a boolean via Boolean.valueOf(String).
209
						// Seems unnecessary to impose any further restrictions.
210
						break;
211
					case AttributeDefinition.CHARACTER :
212
						Character charVal = new Character(s.charAt(0));
213
						if (ad._minValue != null && charVal.compareTo((Character) ad._minValue) < 0) {
214
							rangeError = true;
215
						} else if (ad._maxValue != null && charVal.compareTo((Character) ad._maxValue) > 0) {
216
							rangeError = true;
217
						}
218
						break;
219
					case AttributeDefinition.FLOAT :
220
						Float floatVal = new Float(s);
221
						if (ad._minValue != null && floatVal.compareTo((Float) ad._minValue) < 0) {
222
							rangeError = true;
223
						} else if (ad._maxValue != null && floatVal.compareTo((Float) ad._maxValue) > 0) {
224
							rangeError = true;
225
						}
226
						break;
227
					case AttributeDefinition.SHORT :
228
						Short shortVal = new Short(s);
229
						if (ad._minValue != null && shortVal.compareTo((Short) ad._minValue) < 0) {
230
							rangeError = true;
231
						} else if (ad._maxValue != null && shortVal.compareTo((Short) ad._maxValue) > 0) {
232
							rangeError = true;
233
						}
234
						break;
235
					case AttributeDefinition.BYTE :
236
						Byte byteVal = new Byte(s);
237
						if (ad._minValue != null && byteVal.compareTo((Byte) ad._minValue) < 0) {
238
							rangeError = true;
239
						} else if (ad._maxValue != null && byteVal.compareTo((Byte) ad._maxValue) > 0) {
240
							rangeError = true;
241
						}
242
						break;
243
					case AttributeDefinition.BIGDECIMAL :
244
						BigDecimal bigDecVal = new BigDecimal(s);
245
						if (ad._minValue != null && bigDecVal.compareTo((BigDecimal) ad._minValue) < 0) {
246
							rangeError = true;
247
						} else if (ad._maxValue != null && bigDecVal.compareTo((BigDecimal) ad._maxValue) > 0) {
248
							rangeError = true;
249
						}
250
						break;
251
					case AttributeDefinition.BIGINTEGER :
252
						BigInteger bigIntVal = new BigInteger(s);
253
						if (ad._minValue != null && bigIntVal.compareTo((BigInteger) ad._minValue) < 0) {
254
							rangeError = true;
255
						} else if (ad._maxValue != null && bigIntVal.compareTo((BigInteger) ad._maxValue) > 0) {
256
							rangeError = true;
257
						}
258
						break;
259
					default :
260
						throw new IllegalStateException();
261
				}
262
				if (rangeError) {
263
					return (NLS.bind(MetaTypeMsg.VALUE_OUT_OF_RANGE, s));
264
				}
265
			}
266
			// No problems detected
267
			return ""; //$NON-NLS-1$
268
		} catch (Throwable t) {
269
			String message = NLS.bind(MetaTypeMsg.EXCEPTION_MESSAGE, t.getClass().getName(), t.getMessage());
270
			logger.log(LogService.LOG_DEBUG, message, t);
271
			return message;
272
		}
273
	}
274
}

Return to bug 349711