You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by fm...@apache.org on 2007/04/11 20:27:14 UTC

svn commit: r527597 [2/2] - in /incubator/felix/trunk/metatype: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/felix/ src/main/java/org/apache/felix/metatype/ src/main/java/org/apache/felix/metaty...

Added: incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/LocalizedObjectClassDefinition.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/LocalizedObjectClassDefinition.java?view=auto&rev=527597
==============================================================================
--- incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/LocalizedObjectClassDefinition.java (added)
+++ incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/LocalizedObjectClassDefinition.java Wed Apr 11 11:27:12 2007
@@ -0,0 +1,260 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.metatype.internal;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import org.apache.felix.metatype.AD;
+import org.apache.felix.metatype.OCD;
+import org.apache.felix.metatype.internal.l10n.Resources;
+import org.osgi.framework.Bundle;
+import org.osgi.service.metatype.AttributeDefinition;
+import org.osgi.service.metatype.ObjectClassDefinition;
+
+
+/**
+ * The <code>LocalizedObjectClassDefinition</code> class is the implementation
+ * of the <code>ObjectClassDefinition</code> interface. This class delegates
+ * calls to the underlying {@link OCD} localizing the results of the following
+ * methods: {@link #getName()}, {@link #getDescription()}, and
+ * {@link #getIcon(int)}.
+ * 
+ * @author fmeschbe
+ */
+public class LocalizedObjectClassDefinition extends LocalizedBase implements ObjectClassDefinition
+{
+
+    private Bundle bundle;
+
+    private OCD ocd;
+
+
+    /**
+     * Creates and instance of this localizing facade.
+     * 
+     * @param bundle The <code>Bundle</code> providing this object class
+     *            definition.
+     * @param ocd The {@link OCD} to which calls are delegated.
+     * @param resources The {@link Resources} used to localize return values of
+     * localizable methods.
+     */
+    public LocalizedObjectClassDefinition( Bundle bundle, OCD ocd, Resources resources )
+    {
+        super( resources );
+        this.bundle = bundle;
+        this.ocd = ocd;
+    }
+
+
+    /**
+     * @param filter
+     * @return
+     * @see org.osgi.service.metatype.ObjectClassDefinition#getAttributeDefinitions(int)
+     */
+    public AttributeDefinition[] getAttributeDefinitions( int filter )
+    {
+        if ( ocd.getAttributeDefinitions() == null )
+        {
+            return null;
+        }
+
+        Iterator adhIter = ocd.getAttributeDefinitions().values().iterator();
+        if ( filter == ObjectClassDefinition.OPTIONAL || filter == ObjectClassDefinition.REQUIRED )
+        {
+            boolean required = ( filter == ObjectClassDefinition.REQUIRED );
+            adhIter = new RequiredFilterIterator( adhIter, required );
+        }
+        else if ( filter != ObjectClassDefinition.ALL )
+        {
+            return null;
+        }
+
+        if ( !adhIter.hasNext() )
+        {
+            return null;
+        }
+
+        List result = new ArrayList();
+        while ( adhIter.hasNext() )
+        {
+            result.add( new LocalizedAttributeDefinition( ( AD ) adhIter.next(), getResources() ) );
+        }
+
+        return ( AttributeDefinition[] ) result.toArray( new AttributeDefinition[result.size()] );
+    }
+
+
+    /**
+     * @return
+     * @see org.osgi.service.metatype.ObjectClassDefinition#getDescription()
+     */
+    public String getDescription()
+    {
+        return localize( ocd.getDescription() );
+    }
+
+
+    /**
+     * @param size
+     * @return
+     * @throws IOException
+     * @see org.osgi.service.metatype.ObjectClassDefinition#getIcon(int)
+     */
+    public InputStream getIcon( int size ) throws IOException
+    {
+        // nothing if no icons are defined
+        Map icons = ocd.getIcons();
+        if ( icons == null )
+        {
+            return null;
+        }
+
+        // get exact size
+        String iconPath = ( String ) icons.get( new Integer( size ) );
+        if ( iconPath == null )
+        {
+            // approximate size: largest icon smaller than requested
+            Integer selected = new Integer( Integer.MIN_VALUE );
+            for ( Iterator ei = icons.keySet().iterator(); ei.hasNext(); )
+            {
+                Map.Entry entry = ( Map.Entry ) ei.next();
+                Integer keySize = ( Integer ) entry.getKey();
+                if ( keySize.intValue() <= size && selected.compareTo( keySize ) < 0 )
+                {
+                    selected = keySize;
+                }
+            }
+            // get the raw path, fail if no path can be found
+            iconPath = ( String ) icons.get( selected );
+        }
+
+        // fail if no icon could be found
+        if ( iconPath == null )
+        {
+            return null;
+        }
+
+        // localize the path
+        iconPath = localize( iconPath );
+
+        // try to resolve the path in the bundle
+        URL url = bundle.getEntry( iconPath );
+        if ( url == null )
+        {
+            return null;
+        }
+
+        // open the stream on the URL - this may throw an IOException
+        return url.openStream();
+    }
+
+
+    /**
+     * @return
+     * @see org.osgi.service.metatype.ObjectClassDefinition#getID()
+     */
+    public String getID()
+    {
+        return ocd.getID();
+    }
+
+
+    /**
+     * @return
+     * @see org.osgi.service.metatype.ObjectClassDefinition#getName()
+     */
+    public String getName()
+    {
+        return localize( ocd.getName() );
+    }
+
+    private static class RequiredFilterIterator implements Iterator
+    {
+
+        private final Iterator base;
+
+        private final boolean required;
+
+        private AD next;
+
+
+        private RequiredFilterIterator( Iterator base, boolean required )
+        {
+            this.base = base;
+            this.required = required;
+            this.next = seek();
+        }
+
+
+        public boolean hasNext()
+        {
+            return next != null;
+        }
+
+
+        public Object next()
+        {
+            if ( !hasNext() )
+            {
+                throw new NoSuchElementException();
+            }
+
+            AD toReturn = next;
+            next = seek();
+            return toReturn;
+        }
+
+
+        public void remove()
+        {
+            throw new UnsupportedOperationException( "remove" );
+        }
+
+
+        private AD seek()
+        {
+            if ( base.hasNext() )
+            {
+                AD next;
+                do
+                {
+                    next = ( AD ) base.next();
+                }
+                while ( next.isRequired() != required && base.hasNext() );
+
+                if ( next.isRequired() == required )
+                {
+                    return next;
+                }
+            }
+
+            // nothing found any more
+            return null;
+        }
+
+    }
+}

Propchange: incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/LocalizedObjectClassDefinition.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/LocalizedObjectClassDefinition.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/MetaTypeInformationImpl.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/MetaTypeInformationImpl.java?view=auto&rev=527597
==============================================================================
--- incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/MetaTypeInformationImpl.java (added)
+++ incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/MetaTypeInformationImpl.java Wed Apr 11 11:27:12 2007
@@ -0,0 +1,215 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.metatype.internal;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.felix.metatype.DefaultMetaTypeProvider;
+import org.apache.felix.metatype.Designate;
+import org.apache.felix.metatype.DesignateObject;
+import org.apache.felix.metatype.MetaData;
+import org.apache.felix.metatype.OCD;
+import org.osgi.framework.Bundle;
+import org.osgi.service.metatype.MetaTypeInformation;
+import org.osgi.service.metatype.MetaTypeProvider;
+import org.osgi.service.metatype.ObjectClassDefinition;
+
+/**
+ * The <code>MetaTypeInformationImpl</code> class implements the
+ * <code>MetaTypeInformation</code> interface returned from the
+ * <code>MetaTypeService</code>.
+ * 
+ * @author fmeschbe
+ */
+public class MetaTypeInformationImpl implements MetaTypeInformation {
+
+    // also defined in org.osgi.service.cm.ConfigurationAdmin, but copied
+    // here to not create a synthetic dependency
+    public static final String SERVICE_FACTORYPID = "service.factoryPid";
+
+    private final Bundle bundle;
+
+    private Set pids;
+
+    private Set factoryPids;
+
+    private Set locales;
+
+    private Map metaTypeProviders;
+
+    protected MetaTypeInformationImpl(Bundle bundle) {
+        this.bundle = bundle;
+        this.pids = new TreeSet();
+        this.factoryPids = new TreeSet();
+        this.metaTypeProviders = new HashMap();
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.osgi.service.metatype.MetaTypeInformation#getBundle()
+     */
+    public Bundle getBundle() {
+        return bundle;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.osgi.service.metatype.MetaTypeInformation#getFactoryPids()
+     */
+    public String[] getFactoryPids() {
+        return (String[]) factoryPids.toArray(new String[factoryPids.size()]);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.osgi.service.metatype.MetaTypeInformation#getPids()
+     */
+    public String[] getPids() {
+        return (String[]) pids.toArray(new String[pids.size()]);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.osgi.service.metatype.MetaTypeProvider#getLocales()
+     */
+    public String[] getLocales() {
+        if (locales == null) {
+            synchronized (this) {
+                Set newLocales = new TreeSet();
+                for (Iterator mi = metaTypeProviders.values().iterator(); mi.hasNext();) {
+                    MetaTypeProvider mtp = (MetaTypeProvider) mi.next();
+                    addValues(newLocales, mtp.getLocales());
+                }
+                locales = newLocales;
+            }
+        }
+
+        return (String[]) locales.toArray(new String[locales.size()]);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.osgi.service.metatype.MetaTypeProvider#getObjectClassDefinition(java.lang.String,
+     *      java.lang.String)
+     */
+    public ObjectClassDefinition getObjectClassDefinition(String id,
+            String locale) {
+        MetaTypeProvider mtp = (MetaTypeProvider) metaTypeProviders.get(id);
+        return (mtp != null) ? mtp.getObjectClassDefinition(id, locale) : null;
+    }
+    
+    // ---------- internal support for metadata -------------------------------
+
+    Designate getDesignate( String pid )
+    {
+        Object mto = metaTypeProviders.get( pid );
+        if ( mto instanceof DefaultMetaTypeProvider )
+        {
+            return ( ( DefaultMetaTypeProvider ) mto ).getDesignate( pid );
+        }
+
+        return null;
+    }
+    
+    // ---------- setters to fill the values -----------------------------------
+
+    protected void addMetaData(MetaData md) {
+        if (md.getDesignates() != null) {
+            // meta type provide to register by PID
+            DefaultMetaTypeProvider dmtp = new DefaultMetaTypeProvider(bundle, md);
+            
+            Iterator designates = md.getDesignates().values().iterator();
+            while (designates.hasNext()) {
+                Designate designate = (Designate) designates.next();
+
+                // get the OCD reference, ignore the designate if none
+                DesignateObject object = designate.getObject();
+                String ocdRef = (object == null) ? null : object.getOcdRef();
+                if (ocdRef == null) {
+                    continue;
+                }
+
+                // get ocd for the reference, ignore designate if none
+                OCD ocd = (OCD) md.getObjectClassDefinitions().get(ocdRef);
+                if (ocd == null) {
+                    continue;
+                }
+
+                // gather pids and factory pids
+                pids.add(designate.getPid());
+                if (designate.getFactoryPid() != null) {
+                    factoryPids.add( designate.getFactoryPid() );
+                }
+
+                // register a metatype provider for the pid
+                addMetaTypeProvider(designate.getPid(), dmtp);
+            }
+        }
+    }
+
+    protected void addPids(String[] pids) {
+        addValues(this.pids, pids);
+    }
+
+    protected void removePid(String pid) {
+        this.pids.remove(pid);
+    }
+
+    protected void addFactoryPids(String[] factoryPids) {
+        addValues(this.factoryPids, factoryPids);
+    }
+
+    protected void removeFactoryPid(String factoryPid) {
+        this.factoryPids.remove(factoryPid);
+    }
+
+    protected void addMetaTypeProvider(String key, MetaTypeProvider mtp) {
+        if (key != null && mtp != null) {
+            metaTypeProviders.put(key, mtp);
+            locales = null;
+        }
+    }
+
+    protected MetaTypeProvider removeMetaTypeProvider(String key) {
+        if (key != null) {
+            locales = null;
+            return (MetaTypeProvider) metaTypeProviders.remove(key);
+        }
+
+        return null;
+    }
+
+    private void addValues(Collection dest, Object[] values) {
+        if (values != null && values.length > 0) {
+            dest.addAll(Arrays.asList(values));
+        }
+    }
+}

Propchange: incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/MetaTypeInformationImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/MetaTypeInformationImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/MetaTypeServiceImpl.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/MetaTypeServiceImpl.java?view=auto&rev=527597
==============================================================================
--- incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/MetaTypeServiceImpl.java (added)
+++ incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/MetaTypeServiceImpl.java Wed Apr 11 11:27:12 2007
@@ -0,0 +1,118 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.metatype.internal;
+
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Enumeration;
+
+import org.apache.felix.metatype.MetaData;
+import org.apache.felix.metatype.MetaDataReader;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+import org.osgi.service.metatype.MetaTypeInformation;
+import org.osgi.service.metatype.MetaTypeService;
+import org.xmlpull.v1.XmlPullParserException;
+
+
+/**
+ * The <code>MetaTypeServiceImpl</code> class is the implementation of the
+ * <code>MetaTypeService</code> interface of the OSGi Metatype Service
+ * Specification 1.1.  
+ *
+ * @author fmeschbe
+ */
+class MetaTypeServiceImpl implements MetaTypeService
+{
+
+    /** The <code>BundleContext</code> of the providing this service. */
+    private final BundleContext bundleContext;
+
+
+    /**
+     * Creates an instance of this class.
+     * 
+     * @param bundleContext The <code>BundleContext</code> ultimately used to
+     *      access services if there are no meta type documents. 
+     */
+    MetaTypeServiceImpl( BundleContext bundleContext )
+    {
+        this.bundleContext = bundleContext;
+    }
+
+
+    /**
+     * Looks for meta type documents in the given <code>bundle</code>. If no
+     * such documents exist, a <code>MetaTypeInformation</code> object is
+     * returned handling the services of the bundle.
+     * <p>
+     * According to the specification, the services of the bundle are ignored
+     * if at least one meta type document exists.
+     * 
+     * @param bundle The <code>Bundle</code> for which a
+     *      <code>MetaTypeInformation</code> is to be returned.
+     */
+    public MetaTypeInformation getMetaTypeInformation( Bundle bundle )
+    {
+        MetaTypeInformation mti = fromDocuments( bundle );
+        if ( mti != null )
+        {
+            return mti;
+        }
+
+        return new ServiceMetaTypeInformation( bundleContext, bundle );
+    }
+
+
+    private MetaTypeInformation fromDocuments( Bundle bundle )
+    {
+        MetaDataReader reader = new MetaDataReader();
+
+        // get the descriptors, return nothing if none
+        Enumeration docs = bundle.findEntries( METATYPE_DOCUMENTS_LOCATION, "*.xml", false );
+        if ( docs == null || !docs.hasMoreElements() )
+        {
+            return null;
+        }
+
+        MetaTypeInformationImpl cmti = new MetaTypeInformationImpl( bundle );
+        while ( docs.hasMoreElements() )
+        {
+            URL doc = ( URL ) docs.nextElement();
+            try
+            {
+                MetaData metaData = reader.parse( doc );
+                if (metaData != null) {
+                    cmti.addMetaData( metaData );
+                }
+            }
+            catch ( XmlPullParserException xppe )
+            {
+                Activator.log( LogService.LOG_ERROR, "fromDocuments: Error parsing document " + doc, xppe );
+            }
+            catch ( IOException ioe )
+            {
+                Activator.log( LogService.LOG_ERROR, "fromDocuments: Error accessing document " + doc, ioe );
+            }
+        }
+        return cmti;
+    }
+}

Propchange: incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/MetaTypeServiceImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/MetaTypeServiceImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/ServiceMetaTypeInformation.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/ServiceMetaTypeInformation.java?view=auto&rev=527597
==============================================================================
--- incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/ServiceMetaTypeInformation.java (added)
+++ incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/ServiceMetaTypeInformation.java Wed Apr 11 11:27:12 2007
@@ -0,0 +1,238 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.metatype.internal;
+
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+import org.osgi.service.metatype.MetaTypeProvider;
+
+
+/**
+ * The <code>ServiceMetaTypeInformation</code> extends the
+ * {@link CompoundMetaTypeInformation} adding support to register and unregister
+ * <code>ManagedService</code>s and <code>ManagedServiceFactory</code>s
+ * also implementing the <code>MetaTypeProvider</code> interface.
+ * 
+ * @author fmeschbe
+ */
+public class ServiceMetaTypeInformation extends MetaTypeInformationImpl implements ServiceListener
+{
+
+    /**
+     * The filter specification to find <code>ManagedService</code>s and
+     * <code>ManagedServiceFactory</code>s as well as to register a service
+     * listener for those services (value is
+     * "(|(objectClass=org.osgi.service.cm.ManagedService)(objectClass=org.osgi.service.cm.ManagedServiceFactory))").
+     * We use the hard coded class name here to not create a dependency on the
+     * ConfigurationAdmin service, which may not be available.
+     */
+    private static final String FILTER = "(|(objectClass=org.osgi.service.cm.ManagedService)(objectClass=org.osgi.service.cm.ManagedServiceFactory))";
+
+    /**
+     * The <code>BundleContext</code> used to get and unget services which
+     * have to be registered and unregistered with the base class.
+     */
+    private final BundleContext bundleContext;
+
+
+    /**
+     * Creates an instance of this class handling services of the given
+     * <code>bundle</code>.
+     * 
+     * @param bundleContext The <code>BundleContext</code> used to get and
+     *            unget services.
+     * @param bundle The <code>Bundle</code> whose services are handled by
+     *            this class.
+     */
+    public ServiceMetaTypeInformation( BundleContext bundleContext, Bundle bundle )
+    {
+        super( bundle );
+
+        this.bundleContext = bundleContext;
+
+        // register for service events for the bundle
+        try
+        {
+            bundleContext.addServiceListener( this, FILTER );
+        }
+        catch ( InvalidSyntaxException ise )
+        {
+            Activator.log( LogService.LOG_ERROR, "ServiceMetaTypeInformation: Cannot register for service events", ise );
+        }
+
+        // prepare the filter to select existing services
+        Filter filter;
+        try
+        {
+            filter = bundleContext.createFilter( FILTER );
+        }
+        catch ( InvalidSyntaxException ise )
+        {
+            Activator.log( LogService.LOG_ERROR, "ServiceMetaTypeInformation: Cannot create filter '" + FILTER + "'",
+                ise );
+            return;
+        }
+
+        // add current services of the bundle
+        ServiceReference[] sr = bundle.getRegisteredServices();
+        if ( sr != null )
+        {
+            for ( int i = 0; i < sr.length; i++ )
+            {
+                if ( filter.match( sr[i] ) )
+                {
+                    addService( sr[i] );
+                }
+            }
+        }
+    }
+
+
+    // ---------- ServiceListener ----------------------------------------------
+
+    /**
+     * Handles service registration and unregistration events ignoring all
+     * services not belonging to the <code>Bundle</code> which is handled by
+     * this instance.
+     * 
+     * @param event The <code>ServiceEvent</code>
+     */
+    public void serviceChanged( ServiceEvent event )
+    {
+        // only care for services of our bundle
+        if ( !getBundle().equals( event.getServiceReference().getBundle() ) )
+        {
+            return;
+        }
+
+        if ( event.getType() == ServiceEvent.REGISTERED )
+        {
+            addService( event.getServiceReference() );
+        }
+        else if ( event.getType() == ServiceEvent.UNREGISTERING )
+        {
+            removeService( event.getServiceReference() );
+        }
+    }
+
+
+    /**
+     * Registers the service described by the <code>serviceRef</code> with
+     * this instance if the service is a <code>MetaTypeProvider</code>
+     * instance and either a <code>service.factoryPid</code> or
+     * <code>service.pid</code> property is set in the service registration
+     * properties.
+     * <p>
+     * If the service is registered, this bundle keeps a reference, which is
+     * ungot when the service is unregistered or this bundle is stopped.
+     * 
+     * @param serviceRef The <code>ServiceReference</code> describing the
+     *            service to be checked and handled.
+     */
+    protected void addService( ServiceReference serviceRef )
+    {
+        Object srv = bundleContext.getService( serviceRef );
+
+        boolean ungetService = true;
+
+        if ( srv instanceof MetaTypeProvider )
+        {
+            MetaTypeProvider mtp = ( MetaTypeProvider ) srv;
+
+            // 1. check for a service factory PID
+            String factoryPid = ( String ) serviceRef.getProperty( SERVICE_FACTORYPID );
+            if ( factoryPid != null )
+            {
+                addFactoryPids( new String[]
+                    { factoryPid } );
+                addMetaTypeProvider( factoryPid, mtp );
+                ungetService = false;
+            }
+            else
+            {
+                // 2. check for a service PID
+                String pid = ( String ) serviceRef.getProperty( Constants.SERVICE_PID );
+                if ( pid != null )
+                {
+                    addPids( new String[]
+                        { pid } );
+                    addMetaTypeProvider( pid, mtp );
+                    ungetService = false;
+                }
+            }
+        }
+
+        if ( ungetService )
+        {
+            bundleContext.ungetService( serviceRef );
+        }
+    }
+
+
+    /**
+     * Unregisters the service described by the <code>serviceRef</code> from
+     * this instance. Unregistration just checks for the
+     * <code>service.factoryPid</code> and <code>service.pid</code> service
+     * properties but does not care whether the service implements the
+     * <code>MetaTypeProvider</code> interface. If the service is registered
+     * it is simply unregistered.
+     * <p>
+     * If the service is actually unregistered the reference retrieved by the
+     * registration method is ungotten.
+     * 
+     * @param serviceRef The <code>ServiceReference</code> describing the
+     *            service to be unregistered.
+     */
+    protected void removeService( ServiceReference serviceRef )
+    {
+        boolean ungetService = false;
+
+        // 1. check for a service factory PID
+        String factoryPid = ( String ) serviceRef.getProperty( SERVICE_FACTORYPID );
+        if ( factoryPid != null )
+        {
+            ungetService = removeMetaTypeProvider( factoryPid ) != null;
+            removeFactoryPid( factoryPid );
+        }
+        else
+        {
+            // 2. check for a service PID
+            String pid = ( String ) serviceRef.getProperty( Constants.SERVICE_PID );
+            if ( pid != null )
+            {
+                ungetService = removeMetaTypeProvider( pid ) != null;
+                removePid( pid );
+            }
+        }
+
+        // 3. drop the service reference
+        if ( ungetService )
+        {
+            bundleContext.ungetService( serviceRef );
+        }
+    }
+}

Propchange: incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/ServiceMetaTypeInformation.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/ServiceMetaTypeInformation.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/l10n/BundleResources.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/l10n/BundleResources.java?view=auto&rev=527597
==============================================================================
--- incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/l10n/BundleResources.java (added)
+++ incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/l10n/BundleResources.java Wed Apr 11 11:27:12 2007
@@ -0,0 +1,221 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.metatype.internal.l10n;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import org.osgi.framework.Bundle;
+
+
+/**
+ * The <code>BundleResources</code> TODO
+ *
+ * @author fmeschbe
+ * @version $Rev:$, $Date:$
+ */
+public class BundleResources
+{
+
+    private Bundle bundle;
+    private long bundleLastModified;
+
+    private Map resourcesByLocale;
+
+    private static Map resourcesByBundle = null;
+
+
+    public static Resources getResources( Bundle bundle, String basename, String locale )
+    {
+        BundleResources bundleResources = null;
+
+        if ( resourcesByBundle != null )
+        {
+            // the bundle has been uninstalled, ensure removed from the cache
+            // and return null (e.g. no resources now)
+            if ( bundle.getState() == Bundle.UNINSTALLED )
+            {
+                resourcesByBundle.remove( new Long( bundle.getBundleId() ) );
+                return null;
+            }
+
+            // else check whether we know the bundle already
+            bundleResources = ( BundleResources ) resourcesByBundle.get( new Long( bundle.getBundleId() ) );
+        }
+        else
+        {
+            // create the cache to be used for a newly created BundleResources
+            resourcesByBundle = new HashMap();
+        }
+
+        if ( bundleResources == null )
+        {
+            bundleResources = new BundleResources( bundle );
+            resourcesByBundle.put( new Long( bundle.getBundleId() ), bundleResources );
+        }
+
+        return bundleResources.getResources( basename, locale );
+    }
+
+
+    public static void clearResourcesCache()
+    {
+        resourcesByBundle = null;
+    }
+
+
+    private BundleResources( Bundle bundle )
+    {
+        this.bundle = bundle;
+        this.bundleLastModified = bundle.getLastModified();
+        this.resourcesByLocale = new HashMap();
+    }
+
+
+    private boolean isUpToDate()
+    {
+        return bundle.getState() != Bundle.UNINSTALLED && bundleLastModified >= bundle.getLastModified();
+    }
+
+
+    private Resources getResources( String basename, String locale )
+    {
+        // ensure locale - use VM default locale if null
+        if ( locale == null )
+        {
+            locale = Locale.getDefault().toString();
+        }
+
+        // check the cache, if the bundle has not changed
+        if ( isUpToDate() )
+        {
+            Resources res = ( Resources ) resourcesByLocale.get( locale );
+            if ( res != null )
+            {
+                return res;
+            }
+        }
+        else
+        {
+            // otherwise clear the cache
+            resourcesByLocale.clear();
+        }
+
+        // get the list of potential resource names files
+        Properties parentProperties = null;
+        List resList = createResourceList( locale );
+        for ( Iterator ri = resList.iterator(); ri.hasNext(); )
+        {
+            String tmpLocale = ( String ) ri.next();
+            Resources res = ( Resources ) resourcesByLocale.get( tmpLocale );
+            if ( res != null )
+            {
+                parentProperties = res.getResources();
+            }
+            else
+            {
+                Properties props = loadProperties( basename, tmpLocale, parentProperties );
+                res = new Resources( tmpLocale, props );
+                resourcesByLocale.put( tmpLocale, res );
+                parentProperties = props;
+            }
+        }
+
+        // just return from the cache again
+        return ( Resources ) resourcesByLocale.get( locale );
+    }
+
+
+    private Properties loadProperties( String basename, String locale, Properties parentProperties )
+    {
+        String resourceName = basename;
+        if ( locale != null && locale.length() > 0 )
+        {
+            resourceName += "_" + locale;
+        }
+        resourceName += ".properties";
+
+        Properties props = new Properties( parentProperties );
+        URL resURL = bundle.getEntry( resourceName );
+        if ( resURL != null )
+        {
+            InputStream ins = null;
+            try
+            {
+                ins = resURL.openStream();
+                props.load( ins );
+            }
+            catch ( IOException ex )
+            {
+                // File doesn't exist, just continue loop
+            }
+            finally
+            {
+                if ( ins != null )
+                {
+                    try
+                    {
+                        ins.close();
+                    }
+                    catch ( IOException ignore )
+                    {
+                    }
+                }
+            }
+        }
+
+        return props;
+    }
+
+
+    private List createResourceList( String locale )
+    {
+        List result = new ArrayList( 4 );
+
+        StringTokenizer tokens;
+        StringBuffer tempLocale = new StringBuffer();
+
+        result.add( tempLocale.toString() );
+
+        if ( locale != null && locale.length() > 0 )
+        {
+            tokens = new StringTokenizer( locale, "_" );
+            while ( tokens.hasMoreTokens() )
+            {
+                if ( tempLocale.length() > 0 )
+                {
+                    tempLocale.append( "_" );
+                }
+                tempLocale.append( tokens.nextToken() );
+                result.add( tempLocale.toString() );
+            }
+        }
+        return result;
+    }
+}

Propchange: incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/l10n/BundleResources.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/l10n/BundleResources.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/l10n/Resources.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/l10n/Resources.java?view=auto&rev=527597
==============================================================================
--- incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/l10n/Resources.java (added)
+++ incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/l10n/Resources.java Wed Apr 11 11:27:12 2007
@@ -0,0 +1,50 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.metatype.internal.l10n;
+
+import java.util.Properties;
+
+/**
+ * The <code>Resources</code> TODO
+ *
+ * @author fmeschbe
+ */
+public class Resources
+{
+
+    private String locale;
+    private Properties resources;
+    
+    Resources(String locale, Properties resources) {
+        this.locale = locale;
+        this.resources = resources;
+    }
+    
+    public String getLocale() {
+        return locale;
+    }
+    
+    Properties getResources() {
+        return resources;
+    }
+    
+    public String getResource(String resourceName) {
+        return  resources.getProperty( resourceName, resourceName );
+    }
+}

Propchange: incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/l10n/Resources.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/felix/trunk/metatype/src/main/java/org/apache/felix/metatype/internal/l10n/Resources.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/ADTest.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/ADTest.java?view=auto&rev=527597
==============================================================================
--- incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/ADTest.java (added)
+++ incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/ADTest.java Wed Apr 11 11:27:12 2007
@@ -0,0 +1,133 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.metatype;
+
+
+import junit.framework.TestCase;
+
+import org.osgi.service.metatype.AttributeDefinition;
+
+
+/**
+ * The <code>ADTest</code> class tests the static helper methods of the
+ * {@link AD} class.
+ * 
+ * @author fmeschbe
+ */
+public class ADTest extends TestCase
+{
+
+    private static final String BLANK = "     \r\n   \t";
+
+
+    public void testNull()
+    {
+        String listString = null;
+        String[] list = AD.splitList( listString );
+        assertNull( list );
+    }
+
+
+    public void testEmpty()
+    {
+        String listString = "";
+        String[] list = AD.splitList( listString );
+        assertNull( list );
+    }
+
+
+    public void testSingle()
+    {
+        String value0 = "value";
+        String listString = value0;
+        String[] list = AD.splitList( listString );
+        assertNotNull( list );
+        assertEquals( 1, list.length );
+        assertEquals( value0, list[0] );
+    }
+
+
+    public void testTwo()
+    {
+        String value0 = "value0";
+        String value1 = "value1";
+        String listString = value0 + "," + value1;
+        String[] list = AD.splitList( listString );
+        assertNotNull( list );
+        assertEquals( 2, list.length );
+        assertEquals( value0, list[0] );
+        assertEquals( value1, list[1] );
+    }
+
+
+    public void testSingleBlanks()
+    {
+        String value0 = "value";
+        String listString = BLANK + value0 + BLANK;
+        String[] list = AD.splitList( listString );
+        assertNotNull( list );
+        assertEquals( 1, list.length );
+        assertEquals( value0, list[0] );
+    }
+
+
+    public void testTwoBlanks()
+    {
+        String value0 = "value0";
+        String value1 = "value1";
+        String listString = BLANK + value0 + BLANK + "," + BLANK + value1 + BLANK;
+        String[] list = AD.splitList( listString );
+        assertNotNull( list );
+        assertEquals( 2, list.length );
+        assertEquals( value0, list[0] );
+        assertEquals( value1, list[1] );
+    }
+
+
+    public void testStandardSample()
+    {
+        String value0 = "a,b";
+        String value1 = "b,c";
+        String value2 = "c\\";
+        String value3 = "d";
+        String listString = "a\\,b,b\\,c, c\\\\,d";
+        String[] list = AD.splitList( listString );
+        assertNotNull( list );
+        assertEquals( 4, list.length );
+        assertEquals( value0, list[0] );
+        assertEquals( value1, list[1] );
+        assertEquals( value2, list[2] );
+        assertEquals( value3, list[3] );
+    }
+
+
+    public void testToTypeString()
+    {
+        assertEquals( AttributeDefinition.STRING, AD.toType( "String" ) );
+        assertEquals( AttributeDefinition.LONG, AD.toType( "Long" ) );
+        assertEquals( AttributeDefinition.DOUBLE, AD.toType( "Double" ) );
+        assertEquals( AttributeDefinition.FLOAT, AD.toType( "Float" ) );
+        assertEquals( AttributeDefinition.INTEGER, AD.toType( "Integer" ) );
+        assertEquals( AttributeDefinition.BYTE, AD.toType( "Byte" ) );
+        assertEquals( AttributeDefinition.CHARACTER, AD.toType( "Char" ) );
+        assertEquals( AttributeDefinition.BOOLEAN, AD.toType( "Boolean" ) );
+        assertEquals( AttributeDefinition.SHORT, AD.toType( "Short" ) );
+        assertEquals( AttributeDefinition.STRING, AD.toType( "JohnDoe" ) );
+    }
+}

Propchange: incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/ADTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/ADTest.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/MetaDataReaderTest.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/MetaDataReaderTest.java?view=auto&rev=527597
==============================================================================
--- incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/MetaDataReaderTest.java (added)
+++ incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/MetaDataReaderTest.java Wed Apr 11 11:27:12 2007
@@ -0,0 +1,152 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.metatype;
+
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+
+import org.osgi.service.metatype.AttributeDefinition;
+import org.xmlpull.v1.XmlPullParserException;
+
+
+/**
+ * The <code>MetaDataReaderTest</code> class tests the
+ * <code>MetaDataReader</code> class.
+ *
+ * @author fmeschbe
+ */
+public class MetaDataReaderTest extends TestCase
+{
+
+    private MetaDataReader reader;
+
+
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+
+        reader = new MetaDataReader();
+    }
+
+
+    protected void tearDown() throws Exception
+    {
+        reader = null;
+
+        super.tearDown();
+    }
+
+
+    public void testEmpty() throws IOException, XmlPullParserException
+    {
+        String empty = "<MetaData />";
+        MetaData mti = read( empty );
+
+        assertNull( mti.getLocalePrefix() );
+        assertNull( mti.getObjectClassDefinitions() );
+    }
+
+
+    public void testEmptyLocalization() throws IOException, XmlPullParserException
+    {
+        String testLoc = "OSGI-INF/folder/base";
+        String empty = "<MetaData localization=\"" + testLoc + "\"/>";
+        MetaData mti = read( empty );
+
+        assertEquals( testLoc, mti.getLocalePrefix() );
+    }
+
+
+    public void testSingleEmptyOCD() throws IOException, XmlPullParserException
+    {
+        String ocdName = "ocd0";
+        String ocdId = "id.ocd0";
+        String ocdDescription = "ocd0 description";
+
+        String empty = "<MetaData><OCD id=\"" + ocdId + "\" name=\"" + ocdName + "\" description=\"" + ocdDescription
+            + "\" /></MetaData>";
+        MetaData mti = read( empty );
+
+        assertNull( mti.getLocalePrefix() );
+        assertNotNull( mti.getObjectClassDefinitions() );
+        assertEquals( 1, mti.getObjectClassDefinitions().size() );
+
+        OCD ocd = ( OCD ) mti.getObjectClassDefinitions().values().iterator().next();
+        assertEquals( ocdId, ocd.getID() );
+        assertEquals( ocdName, ocd.getName() );
+        assertEquals( ocdDescription, ocd.getDescription() );
+
+        assertNull( ocd.getAttributeDefinitions() );
+    }
+
+
+    public void testSingleOCDSingleRequiredAttr() throws IOException, XmlPullParserException
+    {
+        String ocdName = "ocd0";
+        String ocdId = "id.ocd0";
+        String ocdDescription = "ocd0 description";
+
+        String adId = "id.ad0";
+        String adName = "ad0";
+        String adDescription = "ad0 description";
+        String adType = "String";
+        int adCardinality = 789;
+        String adDefault = "    a    ,   b    ,    c    ";
+
+        String empty = "<MetaData>" + "<OCD id=\"" + ocdId + "\" name=\"" + ocdName + "\" description=\""
+            + ocdDescription + "\">" + "<AD id=\"" + adId + "\" name=\"" + adName + "\" type=\"" + adType
+            + "\" description=\"" + adDescription + "\" cardinality=\"" + adCardinality + "\" default=\"" + adDefault
+            + "\">" + "</AD>" + "</OCD>" + "</MetaData>";
+        MetaData mti = read( empty );
+
+        assertNull( mti.getLocalePrefix() );
+        assertNotNull( mti.getObjectClassDefinitions() );
+        assertEquals( 1, mti.getObjectClassDefinitions().size() );
+
+        OCD ocd = ( OCD ) mti.getObjectClassDefinitions().values().iterator().next();
+
+        assertNotNull( ocd.getAttributeDefinitions() );
+        assertEquals( 1, ocd.getAttributeDefinitions().size() );
+
+        AD ad = ( AD ) ocd.getAttributeDefinitions().values().iterator().next();
+        assertEquals( adId, ad.getID() );
+        assertEquals( adName, ad.getName() );
+        assertEquals( adDescription, ad.getDescription() );
+        assertEquals( AttributeDefinition.STRING, ad.getType() );
+        assertEquals( adCardinality, ad.getCardinality() );
+        assertNotNull( ad.getDefaultValue() );
+        assertEquals( 3, ad.getDefaultValue().length );
+
+        String[] defaultValue = ad.getDefaultValue();
+        assertEquals( "a", defaultValue[0] );
+        assertEquals( "b", defaultValue[1] );
+        assertEquals( "c", defaultValue[2] );
+    }
+
+
+    private MetaData read( String data ) throws IOException, XmlPullParserException
+    {
+        InputStream input = new ByteArrayInputStream( data.getBytes( "UTF-8" ) );
+        return reader.parse( input );
+    }
+}

Propchange: incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/MetaDataReaderTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/MetaDataReaderTest.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/MockBundle.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/MockBundle.java?view=auto&rev=527597
==============================================================================
--- incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/MockBundle.java (added)
+++ incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/MockBundle.java Wed Apr 11 11:27:12 2007
@@ -0,0 +1,189 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.metatype;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.NoSuchElementException;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+
+public class MockBundle implements Bundle
+{
+
+    private BundleContext bundleContext;
+    private long bundleId;
+    private String bundleSymbolicName;
+    private Hashtable headers = new Hashtable();
+
+
+    MockBundle( BundleContext bundleContext, long bundleId, String bundleSymbolicName )
+    {
+        this.bundleContext = bundleContext;
+        this.bundleId = bundleId;
+        this.bundleSymbolicName = bundleSymbolicName;
+    }
+
+
+    public BundleContext getBundleContext()
+    {
+        return bundleContext;
+    }
+
+
+    public Enumeration findEntries( String path, String filePattern, boolean recurse )
+    {
+        return new Enumeration()
+        {
+            public boolean hasMoreElements()
+            {
+                return false;
+            }
+
+
+            public java.lang.Object nextElement()
+            {
+                throw new NoSuchElementException();
+            }
+        };
+    }
+
+
+    public long getBundleId()
+    {
+        return bundleId;
+    }
+
+
+    public URL getEntry( String name )
+    {
+        return getResource( name );
+    }
+
+
+    public Enumeration getEntryPaths( String path )
+    {
+        return null;
+    }
+
+
+    public Dictionary getHeaders()
+    {
+        return headers;
+    }
+
+
+    public Dictionary getHeaders( String locale )
+    {
+        return headers;
+    }
+
+
+    public long getLastModified()
+    {
+        return 0;
+    }
+
+
+    public String getLocation()
+    {
+        return "mock";
+    }
+
+
+    public ServiceReference[] getRegisteredServices()
+    {
+        return null;
+    }
+
+
+    public URL getResource( String name )
+    {
+        return getClass().getClassLoader().getResource( name );
+    }
+
+
+    public Enumeration getResources( String name ) throws IOException
+    {
+        return getClass().getClassLoader().getResources( name );
+    }
+
+
+    public ServiceReference[] getServicesInUse()
+    {
+        return null;
+    }
+
+
+    public int getState()
+    {
+        return Bundle.ACTIVE;
+    }
+
+
+    public String getSymbolicName()
+    {
+        return bundleSymbolicName;
+    }
+
+
+    public boolean hasPermission( java.lang.Object permission )
+    {
+        return true;
+    }
+
+
+    public Class loadClass( String name ) throws ClassNotFoundException
+    {
+        return getClass().getClassLoader().loadClass( name );
+    }
+
+
+    public void start()
+    {
+    }
+
+
+    public void stop()
+    {
+    }
+
+
+    public void uninstall()
+    {
+    }
+
+
+    public void update()
+    {
+    }
+
+
+    public void update( InputStream in )
+    {
+    }
+}

Propchange: incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/MockBundle.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/MockBundle.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/MockBundleContext.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/MockBundleContext.java?view=auto&rev=527597
==============================================================================
--- incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/MockBundleContext.java (added)
+++ incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/MockBundleContext.java Wed Apr 11 11:27:12 2007
@@ -0,0 +1,432 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.metatype;
+
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+
+/**
+ * The <code>MockBundleContext</code> TODO
+ *
+ * @author fmeschbe
+ * @version $Rev:$, $Date:$
+ */
+public class MockBundleContext implements BundleContext
+{
+
+    private Bundle theBundle;
+    private Map services;
+
+    private Set serviceListeners;
+
+
+    public MockBundleContext( long bundleId, String bundleSymbolicName )
+    {
+        theBundle = new MockBundle( this, bundleId, bundleSymbolicName );
+        services = new HashMap();
+        serviceListeners = new HashSet();
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#addBundleListener(org.osgi.framework.BundleListener)
+     */
+    public void addBundleListener( BundleListener arg0 )
+    {
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#addFrameworkListener(org.osgi.framework.FrameworkListener)
+     */
+    public void addFrameworkListener( FrameworkListener arg0 )
+    {
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#addServiceListener(org.osgi.framework.ServiceListener)
+     */
+    public void addServiceListener( ServiceListener listener )
+    {
+        serviceListeners.add( listener );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#addServiceListener(org.osgi.framework.ServiceListener, java.lang.String)
+     */
+    public void addServiceListener( ServiceListener listener, String filter )
+    {
+        serviceListeners.add( listener );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#createFilter(java.lang.String)
+     */
+    public Filter createFilter( String arg0 )
+    {
+        return new Filter()
+        {
+
+            public boolean match( ServiceReference arg0 )
+            {
+                return true;
+            }
+
+
+            public boolean match( Dictionary arg0 )
+            {
+                return true;
+            }
+
+
+            public boolean matchCase( Dictionary arg0 )
+            {
+                return true;
+            }
+
+        };
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#getAllServiceReferences(java.lang.String, java.lang.String)
+     */
+    public ServiceReference[] getAllServiceReferences( String arg0, String arg1 )
+    {
+        return null;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#getBundle()
+     */
+    public Bundle getBundle()
+    {
+        return theBundle;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#getBundle(long)
+     */
+    public Bundle getBundle( long bundleId )
+    {
+        if ( bundleId == getBundle().getBundleId() )
+        {
+            return getBundle();
+        }
+
+        return null;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#getBundles()
+     */
+    public Bundle[] getBundles()
+    {
+        return new Bundle[]
+            { getBundle() };
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#getDataFile(java.lang.String)
+     */
+    public File getDataFile( String arg0 )
+    {
+        return null;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#getProperty(java.lang.String)
+     */
+    public String getProperty( String arg0 )
+    {
+        return null;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#getService(org.osgi.framework.ServiceReference)
+     */
+    public Object getService( ServiceReference serviceReference )
+    {
+        if ( serviceReference instanceof MockServiceReference )
+        {
+            return ( ( MockServiceReference ) serviceReference ).getServiceRegistration().getService();
+        }
+
+        return null;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#getServiceReference(java.lang.String)
+     */
+    public ServiceReference getServiceReference( String name )
+    {
+        ServiceRegistration sr = ( ServiceRegistration ) services.get( name );
+        return ( sr != null ) ? sr.getReference() : null;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#getServiceReferences(java.lang.String, java.lang.String)
+     */
+    public ServiceReference[] getServiceReferences( String arg0, String arg1 )
+    {
+        return null;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#installBundle(java.lang.String)
+     */
+    public Bundle installBundle( String arg0 )
+    {
+        return null;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#installBundle(java.lang.String, java.io.InputStream)
+     */
+    public Bundle installBundle( String arg0, InputStream arg1 )
+    {
+        return null;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#registerService(java.lang.String[], java.lang.Object, java.util.Dictionary)
+     */
+    public ServiceRegistration registerService( String[] names, Object service, Dictionary props )
+    {
+        props.put( Constants.OBJECTCLASS, names );
+        ServiceRegistration sr = new MockServiceRegistration( this, service, names, props );
+
+        for ( int i = 0; i < names.length; i++ )
+        {
+            services.put( names[i], sr );
+        }
+
+        fireServiceEvent( sr.getReference(), ServiceEvent.REGISTERED );
+
+        return sr;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#registerService(java.lang.String, java.lang.Object, java.util.Dictionary)
+     */
+    public ServiceRegistration registerService( String name, Object service, Dictionary props )
+    {
+        return registerService( new String[]
+            { name }, service, props );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#removeBundleListener(org.osgi.framework.BundleListener)
+     */
+    public void removeBundleListener( BundleListener arg0 )
+    {
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#removeFrameworkListener(org.osgi.framework.FrameworkListener)
+     */
+    public void removeFrameworkListener( FrameworkListener arg0 )
+    {
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#removeServiceListener(org.osgi.framework.ServiceListener)
+     */
+    public void removeServiceListener( ServiceListener listener )
+    {
+        serviceListeners.remove( listener );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.BundleContext#ungetService(org.osgi.framework.ServiceReference)
+     */
+    public boolean ungetService( ServiceReference serviceReference )
+    {
+        if ( serviceReference instanceof MockServiceReference )
+        {
+            return ( ( MockServiceReference ) serviceReference ).getServiceRegistration().ungetService();
+
+        }
+
+        return false;
+    }
+
+
+    private void fireServiceEvent( ServiceReference ref, int type )
+    {
+        ServiceEvent se = new ServiceEvent( type, ref );
+        for ( Iterator li = serviceListeners.iterator(); li.hasNext(); )
+        {
+            ( ( ServiceListener ) li.next() ).serviceChanged( se );
+        }
+    }
+
+    private static class MockServiceRegistration implements ServiceRegistration
+    {
+
+        private MockBundleContext bundleContext;
+        private Dictionary serviceProps;
+        private String[] serviceNames;
+        private Object service;
+        private ServiceReference serviceRef;
+        int refs;
+
+
+        MockServiceRegistration( MockBundleContext bundleContext, Object service, String[] names, Dictionary props )
+        {
+            this.bundleContext = bundleContext;
+            this.serviceNames = names;
+            this.serviceProps = props;
+            this.service = service;
+            this.serviceRef = new MockServiceReference( this );
+        }
+
+
+        Object getService()
+        {
+            refs++;
+            return service;
+        }
+
+
+        boolean ungetService()
+        {
+            refs--;
+            return refs <= 0;
+        }
+
+
+        public ServiceReference getReference()
+        {
+            return serviceRef;
+        }
+
+
+        public void setProperties( Dictionary props )
+        {
+            serviceProps = props;
+        }
+
+
+        public void unregister()
+        {
+            bundleContext.fireServiceEvent( getReference(), ServiceEvent.UNREGISTERING );
+
+            for ( int i = 0; i < serviceNames.length; i++ )
+            {
+                bundleContext.services.remove( serviceNames[i] );
+            }
+        }
+
+    };
+
+    private static class MockServiceReference implements ServiceReference
+    {
+        private MockServiceRegistration msr;
+
+
+        MockServiceReference( MockServiceRegistration msr )
+        {
+            this.msr = msr;
+        }
+
+
+        MockServiceRegistration getServiceRegistration()
+        {
+            return msr;
+        }
+
+
+        public Bundle getBundle()
+        {
+            return msr.bundleContext.getBundle();
+        }
+
+
+        public Object getProperty( String prop )
+        {
+            return msr.serviceProps.get( prop );
+        }
+
+
+        public String[] getPropertyKeys()
+        {
+            List keys = new ArrayList();
+            for ( Enumeration ke = msr.serviceProps.keys(); ke.hasMoreElements(); )
+            {
+                keys.add( ke.nextElement() );
+            }
+            return ( String[] ) keys.toArray( new String[keys.size()] );
+        }
+
+
+        public Bundle[] getUsingBundles()
+        {
+            return null;
+        }
+
+
+        public boolean isAssignableTo( Bundle arg0, String arg1 )
+        {
+            return false;
+        }
+
+    }
+}

Propchange: incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/MockBundleContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/MockBundleContext.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/internal/MetaTypeServiceImplTest.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/internal/MetaTypeServiceImplTest.java?view=auto&rev=527597
==============================================================================
--- incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/internal/MetaTypeServiceImplTest.java (added)
+++ incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/internal/MetaTypeServiceImplTest.java Wed Apr 11 11:27:12 2007
@@ -0,0 +1,206 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.metatype.internal;
+
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import junit.framework.TestCase;
+
+import org.apache.felix.metatype.MockBundleContext;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.cm.ManagedServiceFactory;
+import org.osgi.service.metatype.MetaTypeInformation;
+import org.osgi.service.metatype.MetaTypeProvider;
+import org.osgi.service.metatype.MetaTypeService;
+import org.osgi.service.metatype.ObjectClassDefinition;
+
+
+/**
+ * The <code>MetaTypeServiceImplTest</code> class tests the
+ * {@link MetaTypeServiceImpl}.
+ *
+ * @author fmeschbe
+ */
+public class MetaTypeServiceImplTest extends TestCase
+{
+
+    BundleContext bundleContext;
+
+
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+        bundleContext = new MockBundleContext( 10, "org.apache.felix.metatype.Mock" );
+        bundleContext.getBundle().start();
+    }
+
+
+    protected void tearDown() throws Exception
+    {
+        bundleContext.getBundle().stop();
+        bundleContext = null;
+
+        super.tearDown();
+    }
+
+
+    public void testEmpty()
+    {
+        MetaTypeService mts = new MetaTypeServiceImpl( bundleContext );
+        MetaTypeInformation mti = mts.getMetaTypeInformation( bundleContext.getBundle() );
+        checkEmpty( mti );
+    }
+
+
+    public void testAfterCretionManagedService()
+    {
+        MetaTypeService mts = new MetaTypeServiceImpl( bundleContext );
+        MetaTypeInformation mti = mts.getMetaTypeInformation( bundleContext.getBundle() );
+
+        // assert still empty
+        checkEmpty( mti );
+
+        // register a service with PID
+        String pid = "testAfterCreation";
+        MockManagedService service = new MockManagedService();
+        Dictionary props = new Hashtable();
+        props.put( Constants.SERVICE_PID, pid );
+        ServiceRegistration sr = bundleContext.registerService( ManagedService.class.getName(), service, props );
+
+        // locales should contain MockMetaTypeProvider.LOCALES
+        assertNotNull( mti.getLocales() );
+        assertTrue( mti.getLocales().length == 1 );
+        assertEquals( MockMetaTypeProvider.LOCALES[0], mti.getLocales()[0] );
+
+        // pids must contain pid
+        assertNotNull( mti.getPids() );
+        assertTrue( mti.getPids().length == 1 );
+        assertEquals( pid, mti.getPids()[0] );
+
+        // factoryPids must be empty
+        assertTrue( mti.getFactoryPids() == null || mti.getFactoryPids().length == 0 );
+
+        // unregister the service
+        sr.unregister();
+
+        // ensure everything is clear now again
+        checkEmpty( mti );
+    }
+
+
+    public void testAfterCretionManagedServiceFactory()
+    {
+        MetaTypeService mts = new MetaTypeServiceImpl( bundleContext );
+        MetaTypeInformation mti = mts.getMetaTypeInformation( bundleContext.getBundle() );
+
+        // assert still empty
+        checkEmpty( mti );
+
+        // register a service with PID
+        String pid = "testAfterCreation";
+        String factoryPid = "testAfterCreation_factory";
+        MockManagedServiceFactory service = new MockManagedServiceFactory();
+        Dictionary props = new Hashtable();
+        props.put( Constants.SERVICE_PID, pid );
+        props.put( ConfigurationAdmin.SERVICE_FACTORYPID, factoryPid );
+        ServiceRegistration sr = bundleContext.registerService( ManagedService.class.getName(), service, props );
+
+        // locales should contain MockMetaTypeProvider.LOCALES
+        assertNotNull( mti.getLocales() );
+        assertTrue( mti.getLocales().length == 1 );
+        assertEquals( MockMetaTypeProvider.LOCALES[0], mti.getLocales()[0] );
+
+        // pids must be empty
+        assertTrue( mti.getPids() == null || mti.getPids().length == 0 );
+
+        // pids must contain pid
+        assertNotNull( mti.getFactoryPids() );
+        assertTrue( mti.getFactoryPids().length == 1 );
+        assertEquals( factoryPid, mti.getFactoryPids()[0] );
+
+        // unregister the service
+        sr.unregister();
+
+        // ensure everything is clear now again
+        checkEmpty( mti );
+    }
+
+
+    private void checkEmpty( MetaTypeInformation mti )
+    {
+        assertEquals( bundleContext.getBundle().getBundleId(), mti.getBundle().getBundleId() );
+        assertTrue( mti.getLocales() == null || mti.getLocales().length == 0 );
+        assertTrue( mti.getPids() == null || mti.getPids().length == 0 );
+        assertTrue( mti.getFactoryPids() == null || mti.getFactoryPids().length == 0 );
+    }
+
+    private static class MockMetaTypeProvider implements MetaTypeProvider
+    {
+
+        static String[] LOCALES =
+            { "en_US" };
+
+
+        public String[] getLocales()
+        {
+            return LOCALES;
+        }
+
+
+        public ObjectClassDefinition getObjectClassDefinition( String arg0, String arg1 )
+        {
+            return null;
+        }
+    }
+
+    private static class MockManagedService extends MockMetaTypeProvider implements ManagedService
+    {
+
+        public void updated( Dictionary arg0 )
+        {
+        }
+
+    }
+
+    private static class MockManagedServiceFactory extends MockMetaTypeProvider implements ManagedServiceFactory
+    {
+
+        public void deleted( String arg0 )
+        {
+        }
+
+
+        public String getName()
+        {
+            return null;
+        }
+
+
+        public void updated( String arg0, Dictionary arg1 )
+        {
+        }
+
+    }
+}

Propchange: incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/internal/MetaTypeServiceImplTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/felix/trunk/metatype/src/test/java/org/apache/felix/metatype/internal/MetaTypeServiceImplTest.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url