You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ui...@apache.org on 2012/02/24 11:47:51 UTC
svn commit: r1293173 [6/8] - in
/felix/sandbox/uiterlix/dependencymanager/core: ./ .externalToolBuilders/
.settings/ 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/fel...
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/AspectFilterIndex.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/AspectFilterIndex.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/AspectFilterIndex.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/AspectFilterIndex.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,269 @@
+/*
+ * 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.dm.impl.index;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.FilterIndex;
+import org.apache.felix.dm.ServiceUtil;
+import org.apache.felix.dm.tracker.ServiceTracker;
+import org.apache.felix.dm.tracker.ServiceTrackerCustomizer;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class AspectFilterIndex implements FilterIndex, ServiceTrackerCustomizer {
+ private static final String FILTER_START = "(&(" + Constants.OBJECTCLASS + "=";
+ private static final String FILTER_SUBSTRING_0 = ")(&(|(!(" + Constants.SERVICE_RANKING + "=*))(" + Constants.SERVICE_RANKING + "<=";
+ private static final String FILTER_SUBSTRING_1 = "))(|(" + Constants.SERVICE_ID + "=";
+ private static final String FILTER_SUBSTRING_2 = ")(" + DependencyManager.ASPECT + "=";
+ private static final String FILTER_END = "))))";
+ private final Object m_lock = new Object();
+ private ServiceTracker m_tracker;
+ private BundleContext m_context;
+ private final Map /* <Long, SortedSet<ServiceReference>> */ m_sidToServiceReferencesMap = new HashMap();
+ private final Map /* <Long, SortedMap<Integer, ServiceListener>> */ m_sidToRankingToListenersMap = new HashMap();
+ private final Map /* <ServiceListener, String> */ m_listenerToFilterMap = new HashMap();
+
+ public void open(BundleContext context) {
+ synchronized (m_lock) {
+ if (m_context != null) {
+ throw new IllegalStateException("Filter already open.");
+ }
+ try {
+ m_tracker = new ServiceTracker(context, context.createFilter("(" + Constants.OBJECTCLASS + "=*)"), this);
+ }
+ catch (InvalidSyntaxException e) {
+ throw new Error();
+ }
+ m_context = context;
+ }
+ m_tracker.open(true, true);
+ }
+
+ public void close() {
+ ServiceTracker tracker;
+ synchronized (m_lock) {
+ if (m_context == null) {
+ throw new IllegalStateException("Filter already closed.");
+ }
+ tracker = m_tracker;
+ m_tracker = null;
+ m_context = null;
+ }
+ tracker.close();
+ }
+
+ public boolean isApplicable(String clazz, String filter) {
+ return getFilterData(clazz, filter) != null;
+ }
+
+ /** Returns a value object with the relevant filter data, or <code>null</code> if this filter was not valid. */
+ private FilterData getFilterData(String clazz, String filter) {
+ // something like:
+ // (&(objectClass=com.beinformed.wiringtest.Model)(&(|(!(service.ranking=*))(service.ranking<=9))(|(service.id=37)(org.apache.felix.dependencymanager.aspect=37))))
+ if ((filter != null)
+ && (filter.startsWith(FILTER_START))
+ && (filter.endsWith(FILTER_END))
+ ) {
+ int i0 = filter.indexOf(FILTER_SUBSTRING_0);
+ if (i0 == -1) {
+ return null;
+ }
+ int i1 = filter.indexOf(FILTER_SUBSTRING_1);
+ if (i1 == -1 || i1 <= i0) {
+ return null;
+ }
+ int i2 = filter.indexOf(FILTER_SUBSTRING_2);
+ if (i2 == -1 || i2 <= i1) {
+ return null;
+ }
+ long sid = Long.parseLong(filter.substring(i1 + FILTER_SUBSTRING_1.length(), i2));
+ long sid2 = Long.parseLong(filter.substring(i2 + FILTER_SUBSTRING_2.length(), filter.length() - FILTER_END.length()));
+ if (sid != sid2) {
+ return null;
+ }
+ FilterData result = new FilterData();
+ result.className = filter.substring(FILTER_START.length(), i0);
+ result.serviceId = sid;
+ result.ranking = Integer.parseInt(filter.substring(i0 + FILTER_SUBSTRING_0.length(), i1));
+ return result;
+ }
+ return null;
+ }
+
+ public List getAllServiceReferences(String clazz, String filter) {
+ List /* <ServiceReference> */ result = new ArrayList();
+ FilterData data = getFilterData(clazz, filter);
+ if (data != null) {
+ SortedSet /* <ServiceReference> */ list = (SortedSet) m_sidToServiceReferencesMap.get(Long.valueOf(data.serviceId));
+ if (list != null) {
+ Iterator iterator = list.iterator();
+ while (iterator.hasNext()) {
+ ServiceReference reference = (ServiceReference) iterator.next();
+ if (ServiceUtil.getRanking(reference) <= data.ranking) {
+ result.add(reference);
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ public void serviceChanged(ServiceEvent event) {
+ List list = new ArrayList();
+ ServiceReference reference = event.getServiceReference();
+ Long sid = ServiceUtil.getServiceIdObject(reference);
+ int ranking = ServiceUtil.getRanking(reference);
+ synchronized (m_sidToRankingToListenersMap) {
+ SortedMap /* <Integer, ServiceListener> */ map = (SortedMap) m_sidToRankingToListenersMap.get(sid);
+ if (map != null) {
+ Iterator iterator = map.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Entry entry = (Entry) iterator.next();
+ if (ranking <= ((Integer) entry.getKey()).intValue()) {
+ list.add((ServiceListener) entry.getValue());
+ }
+ }
+ }
+ }
+ Iterator iterator = list.iterator();
+ while (iterator.hasNext()) {
+ ServiceListener listener = (ServiceListener) iterator.next();
+ listener.serviceChanged(event);
+ }
+ }
+
+ public void addServiceListener(ServiceListener listener, String filter) {
+ FilterData data = getFilterData(null, filter);
+ if (data != null) {
+ Long sidObject = Long.valueOf(data.serviceId);
+ synchronized (m_sidToRankingToListenersMap) {
+ SortedMap /* <Integer, ServiceListener> */ rankingToListenersMap = (SortedMap) m_sidToRankingToListenersMap.get(sidObject);
+ if (rankingToListenersMap == null) {
+ rankingToListenersMap = new TreeMap();
+ m_sidToRankingToListenersMap.put(sidObject, rankingToListenersMap);
+ }
+ rankingToListenersMap.put(Integer.valueOf(data.ranking), listener);
+ m_listenerToFilterMap.put(listener, filter);
+ }
+ }
+ }
+
+ public void removeServiceListener(ServiceListener listener) {
+ synchronized (m_sidToRankingToListenersMap) {
+ String filter = (String) m_listenerToFilterMap.remove(listener);
+ FilterData data = getFilterData(null, filter);
+ if (data != null) {
+ synchronized (m_sidToRankingToListenersMap) {
+ SortedMap /* <Integer, ServiceListener> */ rankingToListenersMap = (SortedMap) m_sidToRankingToListenersMap.get(Long.valueOf(data.serviceId));
+ if (rankingToListenersMap != null) {
+ rankingToListenersMap.remove(Integer.valueOf(data.ranking));
+ }
+ }
+ }
+ }
+ }
+
+ public Object addingService(ServiceReference reference) {
+ BundleContext context;
+ synchronized (m_lock) {
+ context = m_context;
+ }
+ if (context != null) {
+ return context.getService(reference);
+ }
+ else {
+ throw new IllegalStateException("No valid bundle context.");
+ }
+ }
+
+ public void addedService(ServiceReference reference, Object service) {
+ add(reference);
+ }
+
+ public void modifiedService(ServiceReference reference, Object service) {
+ modify(reference);
+ }
+
+ public void removedService(ServiceReference reference, Object service) {
+ remove(reference);
+ }
+
+ public void add(ServiceReference reference) {
+ Long sid = ServiceUtil.getServiceIdObject(reference);
+ synchronized (m_sidToServiceReferencesMap) {
+ Set list = (Set) m_sidToServiceReferencesMap.get(sid);
+ if (list == null) {
+ list = new TreeSet();
+ m_sidToServiceReferencesMap.put(sid, list);
+ }
+ list.add(reference);
+ }
+ }
+
+ public void modify(ServiceReference reference) {
+ remove(reference);
+ add(reference);
+ }
+
+ public void remove(ServiceReference reference) {
+ Long sid = ServiceUtil.getServiceIdObject(reference);
+ synchronized (m_sidToServiceReferencesMap) {
+ Set list = (Set) m_sidToServiceReferencesMap.get(sid);
+ if (list != null) {
+ list.remove(reference);
+ }
+ }
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("AspectFilterIndex[");
+ sb.append("S2R2L: " + m_sidToRankingToListenersMap.size());
+ sb.append(", S2SR: " + m_sidToServiceReferencesMap.size());
+ sb.append(", L2F: " + m_listenerToFilterMap.size());
+ sb.append("]");
+ return sb.toString();
+ }
+
+ /** Structure to hold internal filter data. */
+ private static class FilterData {
+ public String className;
+ public long serviceId;
+ public int ranking;
+ }
+}
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/BundleContextInterceptor.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/BundleContextInterceptor.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/BundleContextInterceptor.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/BundleContextInterceptor.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,137 @@
+/*
+ * 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.dm.impl.index;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.felix.dm.FilterIndex;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class BundleContextInterceptor extends BundleContextInterceptorBase {
+ private final ServiceRegistryCache m_cache;
+
+ public BundleContextInterceptor(ServiceRegistryCache cache, BundleContext context) {
+ super(context);
+ m_cache = cache;
+ }
+
+ public void addServiceListener(ServiceListener listener, String filter) throws InvalidSyntaxException {
+ FilterIndex filterIndex = m_cache.hasFilterIndexFor(null, filter);
+ if (filterIndex != null) {
+ filterIndex.addServiceListener(listener, filter);
+ }
+ else {
+// System.out.println("BCI:Listener " + listener.getClass().getName() + " filter " + filter);
+ m_context.addServiceListener(listener, filter);
+ }
+ }
+
+ public void addServiceListener(ServiceListener listener) {
+ FilterIndex filterIndex = m_cache.hasFilterIndexFor(null, null);
+ if (filterIndex != null) {
+ filterIndex.addServiceListener(listener, null);
+ }
+ else {
+// System.out.println("BCI:Listener " + listener.getClass().getName() + " without filter");
+ m_context.addServiceListener(listener);
+ }
+ }
+
+ public void removeServiceListener(ServiceListener listener) {
+ FilterIndex filterIndex = m_cache.hasFilterIndexFor(null, null);
+ if (filterIndex != null) {
+ filterIndex.removeServiceListener(listener);
+ }
+ else {
+ m_context.removeServiceListener(listener);
+ }
+ }
+
+ public ServiceReference[] getServiceReferences(String clazz, String filter) throws InvalidSyntaxException {
+ // first we ask the cache if there is an index for our request (class and filter combination)
+ FilterIndex filterIndex = m_cache.hasFilterIndexFor(clazz, filter);
+ if (filterIndex != null) {
+ List /* <ServiceReference> */ result = filterIndex.getAllServiceReferences(clazz, filter);
+ Iterator iterator = result.iterator();
+ while (iterator.hasNext()) {
+ ServiceReference reference = (ServiceReference) iterator.next();
+ String[] list = (String[]) reference.getProperty(Constants.OBJECTCLASS);
+ for (int i = 0; i < list.length; i++) {
+ if (!reference.isAssignableTo(m_context.getBundle(), list[i])) {
+ iterator.remove();
+ break;
+ }
+ }
+ }
+ if (result == null || result.size() == 0) {
+ return null;
+ }
+ return (ServiceReference[]) result.toArray(new ServiceReference[result.size()]);
+ }
+ else {
+ // if they don't know, we ask the real bundle context instead
+ return m_context.getServiceReferences(clazz, filter);
+ }
+ }
+
+ public ServiceReference[] getAllServiceReferences(String clazz, String filter) throws InvalidSyntaxException {
+ // first we ask the cache if there is an index for our request (class and filter combination)
+ FilterIndex filterIndex = m_cache.hasFilterIndexFor(clazz, filter);
+ if (filterIndex != null) {
+ List /* <ServiceReference> */ result = filterIndex.getAllServiceReferences(clazz, filter);
+ if (result == null || result.size() == 0) {
+ return null;
+ }
+ return (ServiceReference[]) result.toArray(new ServiceReference[result.size()]);
+ }
+ else {
+ // if they don't know, we ask the real bundle context instead
+ return m_context.getAllServiceReferences(clazz, filter);
+ }
+ }
+
+ public ServiceReference getServiceReference(String clazz) {
+ ServiceReference[] references;
+ try {
+ references = getServiceReferences(clazz, null);
+ if (references == null || references.length == 0) {
+ return null;
+ }
+ Arrays.sort(references);
+ return references[references.length - 1];
+ }
+ catch (InvalidSyntaxException e) {
+ throw new Error("Invalid filter syntax thrown for null filter.", e);
+ }
+ }
+
+ public void serviceChanged(ServiceEvent event) {
+ m_cache.serviceChangedForFilterIndices(event);
+ }
+}
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/BundleContextInterceptorBase.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/BundleContextInterceptorBase.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/BundleContextInterceptorBase.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/BundleContextInterceptorBase.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,163 @@
+/*
+ * 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.dm.impl.index;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Base class for bundle context interceptors that keep track of service listeners and delegate incoming changes to them.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class BundleContextInterceptorBase implements BundleContext, ServiceListener {
+ protected final BundleContext m_context;
+ /** Keeps track of all service listeners and their optional filters. */
+ private final Map /* <ServiceListener, String> */m_serviceListenerFilterMap = new HashMap();
+ private long m_currentVersion = 0;
+ private long m_entryVersion = -1;
+ private Entry[] m_serviceListenerFilterMapEntries;
+
+ public BundleContextInterceptorBase(BundleContext context) {
+ m_context = context;
+ }
+
+ public String getProperty(String key) {
+ return m_context.getProperty(key);
+ }
+
+ public Bundle getBundle() {
+ return m_context.getBundle();
+ }
+
+ public Bundle installBundle(String location) throws BundleException {
+ return m_context.installBundle(location);
+ }
+
+ public Bundle installBundle(String location, InputStream input) throws BundleException {
+ return m_context.installBundle(location, input);
+ }
+
+ public Bundle getBundle(long id) {
+ return m_context.getBundle(id);
+ }
+
+ public Bundle[] getBundles() {
+ return m_context.getBundles();
+ }
+
+ public void addServiceListener(ServiceListener listener, String filter) throws InvalidSyntaxException {
+ synchronized (m_serviceListenerFilterMap) {
+ m_serviceListenerFilterMap.put(listener, filter);
+ m_currentVersion++;
+ }
+ }
+
+ public void addServiceListener(ServiceListener listener) {
+ synchronized (m_serviceListenerFilterMap) {
+ m_serviceListenerFilterMap.put(listener, null);
+ m_currentVersion++;
+ }
+ }
+
+ public void removeServiceListener(ServiceListener listener) {
+ synchronized (m_serviceListenerFilterMap) {
+ m_serviceListenerFilterMap.remove(listener);
+ m_currentVersion++;
+ }
+ }
+
+ public void addBundleListener(BundleListener listener) {
+ m_context.addBundleListener(listener);
+ }
+
+ public void removeBundleListener(BundleListener listener) {
+ m_context.removeBundleListener(listener);
+ }
+
+ public void addFrameworkListener(FrameworkListener listener) {
+ m_context.addFrameworkListener(listener);
+ }
+
+ public void removeFrameworkListener(FrameworkListener listener) {
+ m_context.removeFrameworkListener(listener);
+ }
+
+ public ServiceRegistration registerService(String[] clazzes, Object service, Dictionary properties) {
+ return m_context.registerService(clazzes, service, properties);
+ }
+
+ public ServiceRegistration registerService(String clazz, Object service, Dictionary properties) {
+ return m_context.registerService(clazz, service, properties);
+ }
+
+ public ServiceReference[] getServiceReferences(String clazz, String filter) throws InvalidSyntaxException {
+ return m_context.getServiceReferences(clazz, filter);
+ }
+
+ public ServiceReference[] getAllServiceReferences(String clazz, String filter) throws InvalidSyntaxException {
+ return m_context.getAllServiceReferences(clazz, filter);
+ }
+
+ public ServiceReference getServiceReference(String clazz) {
+ return m_context.getServiceReference(clazz);
+ }
+
+ public Object getService(ServiceReference reference) {
+ return m_context.getService(reference);
+ }
+
+ public boolean ungetService(ServiceReference reference) {
+ return m_context.ungetService(reference);
+ }
+
+ public File getDataFile(String filename) {
+ return m_context.getDataFile(filename);
+ }
+
+ public Filter createFilter(String filter) throws InvalidSyntaxException {
+ return m_context.createFilter(filter);
+ }
+
+ protected Entry[] synchronizeCollection() {
+ // lazy copy on write: we make a new copy only if writes have changed the collection
+ synchronized (m_serviceListenerFilterMap) {
+ if (m_currentVersion != m_entryVersion) {
+ m_serviceListenerFilterMapEntries = (Entry[]) m_serviceListenerFilterMap.entrySet().toArray(new Entry[m_serviceListenerFilterMap.size()]);
+ m_entryVersion = m_currentVersion;
+ }
+ }
+ return m_serviceListenerFilterMapEntries;
+ }
+}
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/FilterIndexBundleContext.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/FilterIndexBundleContext.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/FilterIndexBundleContext.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/FilterIndexBundleContext.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,64 @@
+/*
+ * 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.dm.impl.index;
+
+import java.util.Map.Entry;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FilterIndexBundleContext extends BundleContextInterceptorBase {
+ public FilterIndexBundleContext(BundleContext context) {
+ super(context);
+ }
+
+ public void serviceChanged(ServiceEvent event) {
+ Entry[] entries = synchronizeCollection();
+ for (int i = 0; i < entries.length; i++) {
+ Entry serviceListenerFilterEntry = entries[i];
+ ServiceListener serviceListener = (ServiceListener) serviceListenerFilterEntry.getKey();
+ String filter = (String) serviceListenerFilterEntry.getValue();
+ if (filter == null) {
+ serviceListener.serviceChanged(event);
+ }
+ else {
+ // call service changed on the listener if the filter matches the event
+ // TODO review if we can be smarter here
+ try {
+ if ("(objectClass=*)".equals(filter)) {
+ serviceListener.serviceChanged(event);
+ }
+ else {
+ if (m_context.createFilter(filter).match(event.getServiceReference())) {
+ serviceListener.serviceChanged(event);
+ }
+ }
+ }
+ catch (InvalidSyntaxException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+}
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/MultiPropertyExactFilter.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/MultiPropertyExactFilter.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/MultiPropertyExactFilter.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/MultiPropertyExactFilter.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,427 @@
+/*
+ * 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.dm.impl.index;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+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 java.util.TreeSet;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.felix.dm.FilterIndex;
+import org.apache.felix.dm.tracker.ServiceTracker;
+import org.apache.felix.dm.tracker.ServiceTrackerCustomizer;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MultiPropertyExactFilter implements FilterIndex, ServiceTrackerCustomizer {
+ private final Object m_lock = new Object();
+ private ServiceTracker m_tracker;
+ private BundleContext m_context;
+ private final TreeSet /* <String> */ m_propertyKeys = new TreeSet(String.CASE_INSENSITIVE_ORDER);
+ private final Map /* <String, List<ServiceReference>> */ m_keyToServiceReferencesMap = new HashMap();
+ private final Map /* <String, List<ServiceListener>> */ m_keyToListenersMap = new HashMap();
+ private final Map /* <ServiceListener, String> */ m_listenerToFilterMap = new HashMap();
+
+ public MultiPropertyExactFilter(String[] propertyKeys) {
+ for (int i = 0; i < propertyKeys.length; i++) {
+ m_propertyKeys.add(propertyKeys[i]);
+ }
+ }
+
+ public void open(BundleContext context) {
+ synchronized (m_lock) {
+ if (m_context != null) {
+ throw new IllegalStateException("Filter already open.");
+ }
+ try {
+ m_tracker = new ServiceTracker(context, context.createFilter("(" + Constants.OBJECTCLASS + "=*)"), this);
+ }
+ catch (InvalidSyntaxException e) {
+ throw new Error();
+ }
+ m_context = context;
+ }
+ m_tracker.open(true, true);
+ }
+
+ public void close() {
+ ServiceTracker tracker;
+ synchronized (m_lock) {
+ if (m_context == null) {
+ throw new IllegalStateException("Filter already closed.");
+ }
+ tracker = m_tracker;
+ m_tracker = null;
+ m_context = null;
+ }
+ tracker.close();
+ }
+
+ public List /* <ServiceReference> */ getAllServiceReferences(String clazz, String filter) {
+ List /* <ServiceReference> */ result = new ArrayList();
+ List keys = createKeysFromFilter(clazz, filter);
+ Iterator iterator = keys.iterator();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+ ServiceReference reference;
+ synchronized (m_keyToServiceReferencesMap) {
+ List references = (List) m_keyToServiceReferencesMap.get(key);
+ if (references != null) {
+ result.addAll(references);
+ }
+ }
+ }
+ return result;
+ }
+
+ public Object addingService(ServiceReference reference) {
+ BundleContext context;
+ synchronized (m_lock) {
+ context = m_context;
+ }
+ if (context != null) {
+ return context.getService(reference);
+ }
+ else {
+ throw new IllegalStateException("No valid bundle context.");
+ }
+ }
+
+ public void addedService(ServiceReference reference, Object service) {
+ if (isApplicable(reference.getPropertyKeys())) {
+ add(reference);
+ }
+ }
+
+ public void modifiedService(ServiceReference reference, Object service) {
+ if (isApplicable(reference.getPropertyKeys())) {
+ modify(reference);
+ }
+ }
+
+ public void removedService(ServiceReference reference, Object service) {
+ if (isApplicable(reference.getPropertyKeys())) {
+ remove(reference);
+ }
+ }
+
+ public void add(ServiceReference reference) {
+ List /* <String> */ keys = createKeys(reference);
+ synchronized (m_keyToServiceReferencesMap) {
+ for (int i = 0; i < keys.size(); i++) {
+ List /* <ServiceReference> */ references = (List) m_keyToServiceReferencesMap.get(keys.get(i));
+ if (references == null) {
+ references = new ArrayList();
+ m_keyToServiceReferencesMap.put(keys.get(i), references);
+ }
+ references.add(reference);
+ }
+ }
+ }
+
+ public void modify(ServiceReference reference) {
+ List /* <String> */ keys = createKeys(reference);
+ synchronized (m_keyToServiceReferencesMap) {
+ // TODO this is a quite expensive linear scan over the existing collection
+ // because we first need to remove any existing references and they can be
+ // all over the place :)
+ Iterator iterator = m_keyToServiceReferencesMap.values().iterator();
+ while (iterator.hasNext()) {
+ List /* <ServiceReference> */ list = (List) iterator.next();
+ if (list != null) {
+ Iterator i2 = list.iterator();
+ while (i2.hasNext()) {
+ ServiceReference ref = (ServiceReference) i2.next();
+ if (ref.equals(reference)) {
+ i2.remove();
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < keys.size(); i++) {
+ List /* <ServiceReference> */ references = (List) m_keyToServiceReferencesMap.get(keys.get(i));
+ if (references == null) {
+ references = new ArrayList();
+ m_keyToServiceReferencesMap.put(keys.get(i), references);
+ }
+ references.add(reference);
+ }
+ }
+ }
+
+ public void remove(ServiceReference reference) {
+ List /* <String> */ keys = createKeys(reference);
+ synchronized (m_keyToServiceReferencesMap) {
+ for (int i = 0; i < keys.size(); i++) {
+ List /* <ServiceReference> */ references = (List) m_keyToServiceReferencesMap.get(keys.get(i));
+ if (references != null) {
+ references.remove(reference);
+ }
+ }
+ }
+ }
+
+ public boolean isApplicable(String[] propertyKeys) {
+ TreeSet list = new TreeSet(String.CASE_INSENSITIVE_ORDER);
+ for (int i = 0; i < propertyKeys.length; i++) {
+ list.add(propertyKeys[i]);
+ }
+ Iterator iterator = m_propertyKeys.iterator();
+ while (iterator.hasNext()) {
+ String item = (String) iterator.next();
+ if (!(list.contains(item))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean isApplicable(String clazz, String filter) {
+ // "(&(a=b)(c=d))"
+ // "(&(&(a=b)(c=d))(objC=aaa))"
+ // startsWith "(&" en split in "(x=y)" -> elke x bestaat in m_propertykeys
+
+ // (&(objectClass=xyz)(&(a=x)(b=y)))
+
+ Set /* <String> */found = new HashSet();
+ if (filter != null && filter.startsWith("(&(") && filter.substring(3, 14).equalsIgnoreCase(Constants.OBJECTCLASS) && filter.substring(14, 15).equals("=") && filter.contains(")(&(") && filter.endsWith(")))")) {
+ int i1 = filter.indexOf(")(&(");
+ String className = filter.substring(("(&(" + Constants.OBJECTCLASS + "=").length(), i1);
+ if (!m_propertyKeys.contains(Constants.OBJECTCLASS)) {
+ return false;
+ }
+ else {
+ found.add(Constants.OBJECTCLASS);
+ }
+ String[] parts = filter.substring(i1 + ")(&(".length(), filter.length() - ")))".length()).split("\\)\\(");
+ for (int i = 0; i < parts.length; i++) {
+ String part = parts[i];
+ String[] tuple = part.split("=");
+ if (!m_propertyKeys.contains(tuple[0])) {
+ return false;
+ }
+ else {
+ found.add(tuple[0]);
+ }
+ // TODO check value tuple[1]
+ }
+ return found.size() == m_propertyKeys.size();
+ }
+ else if (filter != null && filter.startsWith("(&(") && filter.endsWith("))")) {
+ String[] parts = filter.substring(3, filter.length() - 2).split("\\)\\(");
+ for (int i = 0; i < parts.length; i++) {
+ String part = parts[i];
+ String[] tuple = part.split("=");
+ if (!m_propertyKeys.contains(tuple[0])) {
+ return false;
+ }
+ else {
+ found.add(tuple[0]);
+ }
+ // TODO check value tuple[1]
+ }
+ return found.size() == m_propertyKeys.size();
+ }
+ else if (filter != null && filter.startsWith("(") && filter.endsWith(")") && m_propertyKeys.size() == 1) { // TODO quick hack
+ String part = filter.substring(1, filter.length() - 1);
+ String[] tuple = part.split("=");
+ if (!m_propertyKeys.contains(tuple[0])) {
+ return false;
+ }
+ else {
+ return true;
+ }
+ }
+ else if (clazz != null && filter == null && m_propertyKeys.size() == 1 && Constants.OBJECTCLASS.equalsIgnoreCase((String) m_propertyKeys.first())) {
+ return true;
+ }
+ return false;
+ }
+
+ private List /* <String> */ createKeys(ServiceReference reference) {
+ List /* <String> */ results = new ArrayList();
+
+ results.add(""); // ???
+
+ String[] keys = reference.getPropertyKeys();
+ Arrays.sort(keys, String.CASE_INSENSITIVE_ORDER);
+ StringBuffer result = new StringBuffer();
+ for (int i = 0; i < keys.length; i++) {
+ String key = keys[i].toLowerCase();
+ if (m_propertyKeys.contains(key)) {
+ Object value = reference.getProperty(key);
+ if (value instanceof String[]) {
+ String[] values = (String[]) value;
+ List newResults = new ArrayList();
+ for (int j = 0; j < values.length; j++) {
+ String val = values[j];
+ for (int k = 0; k < results.size(); k++) {
+ String head = (String) results.get(k);
+ if (head != null && head.length() > 0) {
+ head = head + ";";
+ }
+ newResults.add(head + key + "=" + val);
+ }
+ }
+ results = newResults;
+ }
+ else {
+ for (int k = 0; k < results.size(); k++) {
+ String head = (String) results.get(k);
+ if (head != null && head.length() > 0) {
+ head = head + ";";
+ }
+ results.set(k, head + key + "=" + value);
+ }
+ }
+ }
+ }
+ return results;
+ }
+
+ private List /* <String> */ createKeysFromFilter(String clazz, String filter) {
+ List result = new ArrayList();
+ StringBuffer index = new StringBuffer();
+ Iterator iterator = m_propertyKeys.iterator();
+ while (iterator.hasNext()) {
+ String key = ((String) iterator.next()).toLowerCase();
+ if (index.length() > 0) {
+ index.append(';');
+ }
+ index.append(key);
+ index.append('=');
+ String value = null;
+ if (clazz != null && Constants.OBJECTCLASS.equalsIgnoreCase(key)) {
+ value = clazz;
+ } // (&(obC=a)(&(a=b)(c=d)))
+ if (filter != null) {
+ String startString = "(" + key + "=";
+ int i1 = filter.toLowerCase().indexOf(startString);
+ if (i1 != -1) {
+ int i2 = filter.indexOf(")(", i1);
+ if (i2 == -1) {
+ if (filter.endsWith(")))")) {
+ i2 = filter.length() - 3;
+ }
+ else if (filter.endsWith("))")) {
+ i2 = filter.length() - 2;
+ }
+ else {
+ i2 = filter.length() - 1;
+ }
+ }
+ String value2 = filter.substring(i1 + startString.length(), i2);
+ if (value != null && !value.equals(value2)) {
+ // corner case: someone specified a clazz and
+ // also a filter containing a different clazz
+ return result;
+ }
+ value = value2;
+ }
+ }
+ index.append(value);
+ }
+ result.add(index.toString());
+ return result;
+ }
+
+ public void serviceChanged(ServiceEvent event) {
+ if (isApplicable(event.getServiceReference().getPropertyKeys())) {
+ List /* <String> */ keys = createKeys(event.getServiceReference());
+ List list = new ArrayList();
+ synchronized (m_keyToListenersMap) {
+ for (int i = 0; i < keys.size(); i++) {
+ String key = (String) keys.get(i);
+ List listeners = (List) m_keyToListenersMap.get(key);
+ if (listeners != null) {
+ list.addAll(listeners);
+ }
+ }
+ }
+ if (list != null) {
+ Iterator iterator = list.iterator();
+ while (iterator.hasNext()) {
+ ServiceListener listener = (ServiceListener) iterator.next();
+ listener.serviceChanged(event);
+ }
+ }
+ }
+ }
+
+ public void addServiceListener(ServiceListener listener, String filter) {
+ List keys = createKeysFromFilter(null, filter);
+ Iterator iterator = keys.iterator();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+ synchronized (m_keyToListenersMap) {
+ List /* <ServiceListener> */ listeners = (List) m_keyToListenersMap.get(key);
+ if (listeners == null) {
+ listeners = new CopyOnWriteArrayList();
+ m_keyToListenersMap.put(key, listeners);
+ }
+ listeners.add(listener);
+ m_listenerToFilterMap.put(listener, filter);
+ }
+ }
+ }
+
+ public void removeServiceListener(ServiceListener listener) {
+ synchronized (m_keyToListenersMap) {
+ String filter = (String) m_listenerToFilterMap.remove(listener);
+ List keys = createKeysFromFilter(null, filter);
+ Iterator iterator = keys.iterator();
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+
+ boolean result = filter != null;
+ if (result) {
+ List /* <ServiceListener> */ listeners = (List) m_keyToListenersMap.get(key);
+ if (listeners != null) {
+ listeners.remove(listener);
+ }
+ // TODO actually, if listeners == null that would be strange....
+ }
+ }
+ }
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("MultiPropertyExactFilter[");
+ sb.append("K2L: " + m_keyToListenersMap.size());
+ sb.append(", K2SR: " + m_keyToServiceReferencesMap.size());
+ sb.append(", L2F: " + m_listenerToFilterMap.size());
+ sb.append("]");
+ return sb.toString();
+ }
+}
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/ServiceRegistryCache.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/ServiceRegistryCache.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/ServiceRegistryCache.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/ServiceRegistryCache.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,172 @@
+/*
+ * 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.dm.impl.index;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.felix.dm.FilterIndex;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ServiceRegistryCache implements ServiceListener/*, CommandProvider*/ {
+ private final List /* <FilterIndex> */ m_filterIndexList = new CopyOnWriteArrayList();
+ private final BundleContext m_context;
+ private final FilterIndexBundleContext m_filterIndexBundleContext;
+ private final Map /* <BundleContext, BundleContextInterceptor> */ m_bundleContextInterceptorMap = new HashMap();
+ private long m_currentVersion = 0;
+ private long m_arrayVersion = -1;
+ private BundleContextInterceptor[] m_interceptors = null;
+ private ServiceRegistration m_registration;
+
+
+ public ServiceRegistryCache(BundleContext context) {
+ m_context = context;
+ m_filterIndexBundleContext = new FilterIndexBundleContext(m_context);
+ }
+
+ public void open() {
+ m_context.addServiceListener(this);
+// m_registration = m_context.registerService(CommandProvider.class.getName(), this, null);
+ }
+
+ public void close() {
+// m_registration.unregister();
+ m_context.removeServiceListener(this);
+ }
+
+ public void addFilterIndex(FilterIndex index) {
+ m_filterIndexList.add(index);
+ index.open(m_filterIndexBundleContext);
+ }
+
+ public void removeFilterIndex(FilterIndex index) {
+ index.close();
+ m_filterIndexList.remove(index);
+ }
+
+ public void serviceChanged(ServiceEvent event) {
+ // any incoming event is first dispatched to the list of filter indices
+ m_filterIndexBundleContext.serviceChanged(event);
+ // and then all the other listeners can access it
+ synchronized (m_bundleContextInterceptorMap) {
+ if (m_currentVersion != m_arrayVersion) {
+ // if our copy is out of date, we make a new one
+ m_interceptors = (BundleContextInterceptor[]) m_bundleContextInterceptorMap.values().toArray(new BundleContextInterceptor[m_bundleContextInterceptorMap.size()]);
+ m_arrayVersion = m_currentVersion;
+ }
+ }
+
+ serviceChangedForFilterIndices(event);
+ }
+
+ /** Creates an interceptor for a bundle context that uses our cache. */
+ public BundleContext createBundleContextInterceptor(BundleContext context) {
+ synchronized (m_bundleContextInterceptorMap) {
+ BundleContextInterceptor bundleContextInterceptor = (BundleContextInterceptor) m_bundleContextInterceptorMap.get(context);
+ if (bundleContextInterceptor == null) {
+ bundleContextInterceptor = new BundleContextInterceptor(this, context);
+ m_bundleContextInterceptorMap.put(context, bundleContextInterceptor);
+ m_currentVersion++;
+ // TODO figure out a good way to clean up bundle contexts that are no longer valid so they can be garbage collected
+ }
+ return bundleContextInterceptor;
+ }
+ }
+
+ public FilterIndex hasFilterIndexFor(String clazz, String filter) {
+ Iterator iterator = m_filterIndexList.iterator();
+ while (iterator.hasNext()) {
+ FilterIndex filterIndex = (FilterIndex) iterator.next();
+ if (filterIndex.isApplicable(clazz, filter)) {
+ return filterIndex;
+ }
+ }
+ return null;
+ }
+
+ public void serviceChangedForFilterIndices(ServiceEvent event) {
+ Iterator iterator = m_filterIndexList.iterator();
+ while (iterator.hasNext()) {
+ FilterIndex filterIndex = (FilterIndex) iterator.next();
+ filterIndex.serviceChanged(event);
+ }
+ }
+
+// public void _sc(CommandInterpreter ci) {
+// ci.println(toString());
+// }
+//
+// public void _fi(CommandInterpreter ci) {
+// String arg = ci.nextArgument();
+// if (arg != null) {
+// int x = Integer.parseInt(arg);
+// FilterIndex filterIndex = (FilterIndex) m_filterIndexList.get(x);
+// String a1 = ci.nextArgument();
+// String a2 = null;
+// if (a1 != null) {
+// if ("-".equals(a1)) {
+// a1 = null;
+// }
+// a2 = ci.nextArgument();
+// }
+// if (filterIndex.isApplicable(a1, a2)) {
+// List /* <ServiceReference> */ references = filterIndex.getAllServiceReferences(a1, a2);
+// ci.println("Found " + references.size() + " references:");
+// for (int i = 0; i < references.size(); i++) {
+// ci.println("" + i + " - " + references.get(i));
+// }
+// }
+// else {
+// ci.println("Filter not applicable.");
+// }
+// }
+// else {
+// ci.println("FilterIndices:");
+// Iterator iterator = m_filterIndexList.iterator();
+// int index = 0;
+// while (iterator.hasNext()) {
+// FilterIndex filterIndex = (FilterIndex) iterator.next();
+// ci.println("" + index + " " + filterIndex);
+// index++;
+// }
+// }
+// }
+//
+// public String getHelp() {
+// return "I'm not going to help you!";
+// }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("ServiceRegistryCache[");
+ sb.append("FilterIndices: " + m_filterIndexList.size());
+ sb.append(", BundleContexts intercepted: " + m_bundleContextInterceptorMap.size());
+ sb.append("]");
+ return sb.toString();
+ }
+}
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/AttributeDefinitionImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/AttributeDefinitionImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/AttributeDefinitionImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/AttributeDefinitionImpl.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,76 @@
+/*
+ * 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.dm.impl.metatype;
+
+import org.osgi.service.metatype.AttributeDefinition;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class AttributeDefinitionImpl implements AttributeDefinition {
+ private PropertyMetaDataImpl m_propertyMetaData;
+ private Resource m_resource;
+
+ public AttributeDefinitionImpl(PropertyMetaDataImpl propertyMetaData, Resource resource) {
+ m_propertyMetaData = propertyMetaData;
+ m_resource = resource;
+ }
+
+ public int getCardinality() {
+ return m_propertyMetaData.getCardinality();
+ }
+
+ public String[] getDefaultValue() {
+ return m_propertyMetaData.getDefaults();
+ }
+
+ public String getDescription() {
+ return m_resource.localize(m_propertyMetaData.getDescription());
+ }
+
+ public String getID() {
+ return m_propertyMetaData.getId();
+ }
+
+ public String getName() {
+ return m_resource.localize(m_propertyMetaData.getHeading());
+ }
+
+ public String[] getOptionLabels() {
+ String[] labels = m_propertyMetaData.getOptionLabels();
+ if (labels != null) {
+ for (int i = 0; i < labels.length; i++) {
+ labels[i] = m_resource.localize(labels[i]);
+ }
+ }
+ return labels;
+ }
+
+ public String[] getOptionValues() {
+ return m_propertyMetaData.getOptionValues();
+ }
+
+ public int getType() {
+ return m_propertyMetaData.getType();
+ }
+
+ public String validate(String value) {
+ return null;
+ }
+}
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/MetaTypeProviderImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/MetaTypeProviderImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/MetaTypeProviderImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/MetaTypeProviderImpl.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,258 @@
+/*
+ * 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.dm.impl.metatype;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.TreeSet;
+
+import org.apache.felix.dm.PropertyMetaData;
+import org.apache.felix.dm.impl.Logger;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.cm.ManagedServiceFactory;
+import org.osgi.service.log.LogService;
+import org.osgi.service.metatype.MetaTypeProvider;
+import org.osgi.service.metatype.ObjectClassDefinition;
+
+/**
+ * When a ConfigurationDepdendency is configured with properties metadata, we provide
+ * a specific ManagedService which also implements the MetaTypeProvider interface. This interface
+ * allows the MetaTypeService to retrieve our properties metadata, which will then be handled by webconsole.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MetaTypeProviderImpl implements MetaTypeProvider, ManagedService, ManagedServiceFactory {
+ private ManagedService m_managedServiceDelegate;
+ private ManagedServiceFactory m_managedServiceFactoryDelegate;
+ private List m_propertiesMetaData = new ArrayList();
+ private String m_description;
+ private String m_heading;
+ private String m_localization;
+ private Map m_localesProperties = new HashMap();
+ private Logger m_logger;
+ private BundleContext m_bctx;
+ private String m_pid;
+
+ public MetaTypeProviderImpl(String pid, BundleContext ctx, Logger logger, ManagedService msDelegate, ManagedServiceFactory msfDelegate) {
+ m_pid = pid;
+ m_bctx = ctx;
+ m_logger = logger;
+ m_managedServiceDelegate = msDelegate;
+ m_managedServiceFactoryDelegate = msfDelegate;
+ // Set the default localization file base name (see core specification, in section Localization on page 68).
+ // By default, this file can be stored in OSGI-INF/l10n/bundle.properties (and corresponding localized version
+ // in OSGI-INF/l10n/bundle_en_GB_welsh.properties, OSGI-INF/l10n/bundle_en_GB.properties, etc ...
+ // This default localization property file name can be overriden using the PropertyMetaData.setLocalization method.
+ m_localization = (String) m_bctx.getBundle().getHeaders().get(Constants.BUNDLE_LOCALIZATION);
+ if (m_localization == null) {
+ m_localization = Constants.BUNDLE_LOCALIZATION_DEFAULT_BASENAME;
+ }
+ }
+
+ /**
+ * Registers the metatype information of a given configuration property
+ * @param property
+ */
+ public void add(PropertyMetaData property) {
+ m_propertiesMetaData.add(property);
+ }
+
+ /**
+ * A human readable description of the PID this annotation is associated with. Example: "Configuration for the PrinterService bundle".
+ * @return A human readable description of the PID this annotation is associated with (may be localized)
+ */
+ public void setDescription(String description) {
+ m_description = description;
+ }
+
+ /**
+ * The label used to display the tab name (or section) where the properties are displayed. Example: "Printer Service".
+ * @return The label used to display the tab name where the properties are displayed (may be localized)
+ */
+ public void setName(String heading) {
+ m_heading = heading;
+ }
+
+ /**
+ * Points to the basename of the Properties file that can localize the Meta Type informations.
+ * By default, (e.g. <code>setLocalization("person")</code> would match person_du_NL.properties in the root bundle directory.
+ * The default localization base name for the properties is OSGI-INF/l10n/bundle, but can
+ * be overridden by the manifest Bundle-Localization header (see core specification, in section Localization on page 68).
+ */
+ public void setLocalization(String path) {
+ if (path.endsWith(".properties")) {
+ throw new IllegalArgumentException(
+ "path must point to the base name of the propertie file, "
+ + "excluding local suffixes. For example: "
+ + "foo/bar/person is valid and matches the property file \"foo/bar/person_bundle_en_GB_welsh.properties\"");
+ }
+ m_localization = path.startsWith("/") ? path.substring(1) : path;
+ }
+
+ // --------------- MetaTypeProvider interface -------------------------------------------------
+
+ /**
+ * Returns all the Locales our bundle is containing. For instance, if our bundle contains the following localization files:
+ * OSGI-INF/l10n/bundle_en_GB_welsh.properties and OSGI-INF/l10n/bundle_en_GB.properties, then this method will return
+ * "en_GB", "en_GB_welsh" ...
+ * @return the list of Locale supported by our bundle.
+ */
+ public String[] getLocales() {
+ int lastSlash = m_localization.lastIndexOf("/");
+ String path = (lastSlash == -1) ? "/" : ("/" + m_localization.substring(0, lastSlash - 1));
+ String base = (lastSlash == -1) ? m_localization : m_localization.substring(lastSlash + 1);
+ Enumeration e = m_bctx.getBundle().findEntries(path,
+ base + "*.properties", false);
+ if (e == null) {
+ return null;
+ }
+
+ TreeSet set = new TreeSet();
+ while (e.hasMoreElements()) {
+ // We have found a locale property file in the form of "path/file[_language[_ country[_variation]].properties"
+ // And now, we have to get the "language[_country[_variation]]" part ...
+ URL url = (URL) e.nextElement();
+ String name = url.getPath();
+ name = name.substring(name.lastIndexOf("/") + 1);
+ int underscore = name.indexOf("_");
+ if (underscore != -1) {
+ name = name.substring(underscore + 1, name.length() - ".properties".length());
+ }
+ if (name.length() > 0) {
+ set.add(name);
+ }
+ }
+
+ String[] locales = (String[]) set.toArray(new String[set.size()]);
+ return locales.length == 0 ? null : locales;
+ }
+
+ /**
+ * Returns the ObjectClassDefinition for a given Pid/Locale.
+ */
+ public ObjectClassDefinition getObjectClassDefinition(String id, String locale) {
+ try {
+ // Check if the id matches our PID
+ if (!id.equals(m_pid)) {
+ m_logger.log(LogService.LOG_ERROR, "id " + id + " does not match pid " + m_pid);
+ return null;
+ }
+
+ Properties localeProperties = getLocaleProperties(locale);
+ return new ObjectClassDefinitionImpl(m_pid, m_heading,
+ m_description, m_propertiesMetaData, new Resource(localeProperties));
+ }
+
+ catch (Throwable t) {
+ m_logger.log(
+ Logger.LOG_ERROR,
+ "Unexpected exception while geting ObjectClassDefinition for " + id + " (locale="
+ + locale + ")", t);
+ return null;
+ }
+ }
+
+ /**
+ * We also implements the ManagedService and we just delegates the configuration handling to
+ * our associated ConfigurationDependency.
+ */
+ public void updated(Dictionary properties) throws ConfigurationException {
+ m_managedServiceDelegate.updated(properties);
+ }
+
+ /**
+ * Gets the properties for a given Locale.
+ * @param locale
+ * @return
+ * @throws IOException
+ */
+ private synchronized Properties getLocaleProperties(String locale) throws IOException {
+ locale = locale == null ? Locale.getDefault().toString() : locale;
+ Properties properties = (Properties) m_localesProperties.get(locale);
+ if (properties == null) {
+ properties = new Properties();
+ URL url = m_bctx.getBundle().getEntry(m_localization + ".properties");
+ if (url != null) {
+ loadLocale(properties, url);
+ }
+
+ String path = m_localization;
+ StringTokenizer tok = new StringTokenizer(locale, "_");
+ while (tok.hasMoreTokens()) {
+ path += "_" + tok.nextToken();
+ url = m_bctx.getBundle().getEntry(path + ".properties");
+ if (url != null) {
+ properties = new Properties(properties);
+ loadLocale(properties, url);
+ }
+ }
+ m_localesProperties.put(locale, properties);
+ }
+ return properties;
+ }
+
+ /**
+ * Loads a Locale Properties file.
+ * @param properties
+ * @param url
+ * @throws IOException
+ */
+ private void loadLocale(Properties properties, URL url) throws IOException {
+ InputStream in = null;
+ try {
+ in = url.openStream();
+ properties.load(in);
+ }
+ finally {
+ if (in != null) {
+ try {
+ in.close();
+ }
+ catch (IOException ignored) {
+ }
+ }
+ }
+ }
+
+ // ManagedServiceFactory implementation
+ public void deleted(String pid) {
+ m_managedServiceFactoryDelegate.deleted(pid);
+ }
+
+ public String getName() {
+ return m_pid;
+ }
+
+ public void updated(String pid, Dictionary properties) throws ConfigurationException {
+ m_managedServiceFactoryDelegate.updated(pid, properties);
+ }
+}
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/ObjectClassDefinitionImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/ObjectClassDefinitionImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/ObjectClassDefinitionImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/ObjectClassDefinitionImpl.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,101 @@
+/*
+ * 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.dm.impl.metatype;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.service.metatype.AttributeDefinition;
+import org.osgi.service.metatype.ObjectClassDefinition;
+
+/**
+ * ObjectClassDefinition implementation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ObjectClassDefinitionImpl implements ObjectClassDefinition {
+ // Our OCD name (may be localized)
+ private String m_name;
+
+ // Our OCD description (may be localized)
+ private String m_description;
+
+ // Our OCD id
+ private String m_id;
+
+ // The list of Properties MetaData objects (from DependencyManager API)
+ private List m_propertiesMetaData;
+
+ // The localized resource that can be used when localizing some parameters
+ private Resource m_resource;
+
+ public ObjectClassDefinitionImpl(String id, String name, String description, List propertiesMetaData, Resource resource) {
+ m_id = id;
+ m_name = name;
+ m_description = description;
+ m_propertiesMetaData = propertiesMetaData;
+ m_resource = resource;
+ }
+
+ // --------------------- ObjectClassDefinition ----------------------------------------
+
+ public AttributeDefinition[] getAttributeDefinitions(int filter) {
+ List attrs = new ArrayList();
+ for (int i = 0; i < m_propertiesMetaData.size(); i++) {
+ PropertyMetaDataImpl metaData = (PropertyMetaDataImpl) m_propertiesMetaData.get(i);
+ switch (filter) {
+ case ObjectClassDefinition.ALL:
+ attrs.add(new AttributeDefinitionImpl(metaData, m_resource));
+ break;
+ case ObjectClassDefinition.OPTIONAL:
+ if (!metaData.isRequired()) {
+ attrs.add(new AttributeDefinitionImpl(metaData, m_resource));
+ }
+ break;
+ case ObjectClassDefinition.REQUIRED:
+ if (metaData.isRequired()) {
+ attrs.add(new AttributeDefinitionImpl(metaData, m_resource));
+ }
+ break;
+ }
+ }
+
+ AttributeDefinition[] array = new AttributeDefinitionImpl[attrs.size()];
+ return (AttributeDefinition[]) attrs.toArray(array);
+ }
+
+ public String getDescription() {
+ return m_resource.localize(m_description);
+ }
+
+ public String getID() {
+ return m_id;
+ }
+
+ public InputStream getIcon(int size) throws IOException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getName() {
+ return m_resource.localize(m_name);
+ }
+}
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/PropertyMetaDataImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/PropertyMetaDataImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/PropertyMetaDataImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/PropertyMetaDataImpl.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,204 @@
+/*
+ * 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.dm.impl.metatype;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.dm.PropertyMetaData;
+import org.osgi.service.metatype.AttributeDefinition;
+
+/**
+ * DependencyManager PropertyMetaData Implementation. This class describes meta informations regarding
+ * one given configuration property.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class PropertyMetaDataImpl implements PropertyMetaData {
+ /**
+ * List of option labels (may be localized)
+ */
+ List m_optionsLabels = new ArrayList();
+
+ /**
+ * List of option values
+ */
+ List m_optionsValues = new ArrayList();
+
+ /**
+ * Property cardinality.
+ * @see {@link AttributeDefinition#getCardinality()}
+ */
+ private int m_cardinality;
+
+ /**
+ * Valid default property values
+ */
+ private String[] m_defaults;
+
+ /**
+ * Property description.
+ */
+ private String m_description;
+
+ /**
+ * Property title.
+ */
+ private String m_heading;
+
+ /**
+ * Property unique Id
+ */
+ private String m_id;
+
+ /**
+ * Required flag.
+ */
+ private boolean m_required;
+
+ /**
+ * Property Type.
+ * @see {@link AttributeDefinition#getType()}
+ */
+ private int m_type = AttributeDefinition.STRING;
+
+ /**
+ * Mapping between java types and valid MetaType types.
+ * @see {@link AttributeDefinition#getType()}
+ */
+ private final static Map m_typeMapping = new HashMap() {{
+ put(Boolean.class, new Integer(AttributeDefinition.BOOLEAN));
+ put(Byte.class, new Integer(AttributeDefinition.BYTE));
+ put(Character.class, new Integer(AttributeDefinition.CHARACTER));
+ put(Double.class, new Integer(AttributeDefinition.FLOAT));
+ put(Integer.class, new Integer(AttributeDefinition.INTEGER));
+ put(Long.class, new Integer(AttributeDefinition.LONG));
+ put(Short.class, new Integer(AttributeDefinition.SHORT));
+ put(String.class, new Integer(AttributeDefinition.STRING));
+ }};
+
+ public PropertyMetaData addOption(String optionLabel, String optionValue) {
+ m_optionsLabels.add(optionLabel);
+ m_optionsValues.add(optionValue);
+ return this;
+ }
+
+ public PropertyMetaData setCardinality(int cardinality) {
+ m_cardinality = cardinality;
+ return this;
+ }
+
+ public PropertyMetaData setDefaults(String[] defaults) {
+ m_defaults = defaults;
+ return this;
+ }
+
+ public PropertyMetaData setDescription(String description) {
+ m_description = description;
+ return this;
+ }
+
+ public PropertyMetaData setHeading(String heading) {
+ m_heading = heading;
+ return this;
+ }
+
+ public PropertyMetaData setId(String id) {
+ m_id = id;
+ return this;
+ }
+
+ public PropertyMetaData setRequired(boolean required) {
+ m_required = required;
+ return this;
+ }
+
+ public PropertyMetaData setType(Class classType) {
+ Integer type = (Integer) m_typeMapping.get(classType);
+ if (type == null) {
+ throw new IllegalArgumentException("Invalid type: " + classType + ". Valid types are "
+ + m_typeMapping.keySet());
+ }
+ m_type = type.intValue();
+ return this;
+ }
+
+ public String[] getOptionLabels() {
+ String[] optionLabels = new String[m_optionsLabels.size()];
+ return (String[]) m_optionsLabels.toArray(optionLabels);
+ }
+
+ public String[] getOptionValues() {
+ String[] optionValues = new String[m_optionsValues.size()];
+ return (String[]) m_optionsValues.toArray(optionValues);
+ }
+
+ public int getCardinality() {
+ return m_cardinality;
+ }
+
+ public String[] getDefaults() {
+ return m_defaults;
+ }
+
+ public String getDescription() {
+ return m_description;
+ }
+
+ public String getHeading() {
+ return m_heading;
+ }
+
+ public String getId() {
+ return m_id;
+ }
+
+ public boolean isRequired() {
+ return m_required;
+ }
+
+ public int getType() {
+ return m_type;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("cardinality=").append(m_cardinality);
+ sb.append("; defaults=");
+ for (int i = 0; i < m_defaults.length; i ++) {
+ sb.append(m_defaults[i]).append(" ");
+ }
+ sb.append("; description=").append(m_description);
+ sb.append("; heading=").append(m_heading);
+ sb.append("; id=").append(m_id);
+ sb.append("; required=").append(m_required);
+ sb.append("; type=").append(getType());
+ sb.append("; optionLabels=");
+ for (int i = 0; i < m_optionsLabels.size(); i ++) {
+ sb.append(m_optionsLabels.get(i)).append(" ");
+ }
+ sb.append("; optionValues=");
+ for (int i = 0; i < m_optionsValues.size(); i ++) {
+ sb.append(m_optionsValues.get(i)).append(" ");
+ }
+ return sb.toString();
+ }
+}
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/Resource.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/Resource.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/Resource.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/Resource.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,42 @@
+/*
+ * 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.dm.impl.metatype;
+
+import java.util.Properties;
+
+/**
+ * Helper class used to localize a given Property Meta Data.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Resource {
+ private Properties m_properties;
+
+ public Resource(Properties properties) {
+ m_properties = properties;
+ }
+
+ public String localize(String param) {
+ if (m_properties != null && param != null && param.startsWith("%")) {
+ param = param.substring(1);
+ return m_properties.getProperty(param);
+ }
+ return param;
+ }
+}