/* * 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.runtime.itest.components; import java.net.URL; import java.util.Dictionary; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import org.apache.felix.dm.DependencyManager; import org.apache.felix.dm.ResourceHandler; import org.apache.felix.dm.ResourceUtil; import org.apache.felix.dm.annotation.api.Component; import org.apache.felix.dm.annotation.api.Destroy; import org.apache.felix.dm.annotation.api.Init; import org.apache.felix.dm.annotation.api.Inject; import org.apache.felix.dm.annotation.api.Property; import org.apache.felix.dm.annotation.api.ResourceAdapterService; import org.apache.felix.dm.annotation.api.ResourceDependency; import org.apache.felix.dm.annotation.api.ServiceDependency; import org.apache.felix.dm.annotation.api.Start; import org.apache.felix.dm.annotation.api.Stop; import org.apache.felix.dm.itest.util.Ensure; import org.junit.Assert; import org.osgi.framework.BundleContext; import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; /** * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> */ @SuppressWarnings({"rawtypes"}) public class ResourceAnnotation { public final static String ENSURE_RESOURCE = "ResourceAnnotation.resource"; public final static String ENSURE_FIELD = "ResourceAnnotation.field"; public final static String ENSURE_ADAPTER = "ResourceAnnotation.adapter"; public final static String ENSURE_PROVIDER = "ResourceAnnotation.provider"; /** * A Service provided the ServiceProvider, which is a ResourceAdapter. */ public interface ServiceInterface extends Runnable { } /** * A Component which has a resource dependency. */ @Component public static class ResourceConsumer { @ServiceDependency(required = true, filter = "(name=" + ENSURE_RESOURCE + ")") volatile Ensure m_sequencer; private volatile int m_resourcesSeen; @Start void start() { System.out.println("ResourceConsumer.start: sequencer=" + m_sequencer); } @ResourceDependency(required = false, filter = "(&(path=/path/to/*.txt)(host=localhost))") public void add(URL resource) { System.out.println("ResourceConsumer.add: resource=" + resource + ", m_sequencer=" + m_sequencer); if (match(resource, "file://localhost/path/to/test1.txt")) { m_resourcesSeen++; return; } if (match(resource, "file://localhost/path/to/test2.txt")) { m_resourcesSeen++; return; } Assert.fail("Got unexpected resource: " + resource); } private boolean match(URL resource, String url) { return url.equals(resource.toString()); } @Stop void stop() { System.out.println("ResourceConsumer.stop: m_sequencer=" + m_sequencer); Assert.assertEquals(2, m_resourcesSeen); m_sequencer.step(1); } } /** * A Component which as a resource dependency, using a class field. */ @Component public static class ResourceConsumerField { @ServiceDependency(required = true, filter = "(name=" + ENSURE_FIELD + ")") volatile Ensure m_sequencer; @ResourceDependency(filter = "(&(path=*/test1.txt)(host=localhost))") URL m_resource; @Init void init() { if (m_resource != null) { Assert.assertTrue("file://localhost/path/to/test1.txt".equals(m_resource.toString())); m_sequencer.step(1); } } } /** * Provides some simple resources. */ @Component public static class ResourceProvider { @ServiceDependency(required = true, filter = "(name=" + ENSURE_PROVIDER + ")") volatile Ensure m_sequencer; @Inject private volatile BundleContext m_context; private final Map m_handlers = new HashMap(); private final URL[] m_resources; public ResourceProvider() throws Exception { m_resources = new URL[]{ new URL("file://localhost/path/to/test1.txt"), new URL("file://localhost/path/to/test2.txt"), new URL("file://localhost/path/to/README.doc")}; } /** * Handles a new Resource consumer * @param serviceProperties * @param handler */ @SuppressWarnings("unchecked") @ServiceDependency(removed = "remove", required = false) public void add(Map serviceProperties, ResourceHandler handler) { System.out.println("ResourceProvider.addResourceHandler " + handler); String filterString = (String) serviceProperties.get("filter"); Filter filter = null; if (filterString != null) { try { filter = m_context.createFilter(filterString); } catch (InvalidSyntaxException e) { Assert.fail("Could not create filter for resource handler: " + e); return; } } synchronized (m_handlers) { m_handlers.put(handler, filter); } for (int i = 0; i < m_resources.length; i++) { if (filter == null || filter.match((Dictionary<String, ?>) ResourceUtil.createProperties(m_resources[i]))) { System.out.println("ResourceProvider: calling handled.added(" + m_resources[i] + ")"); handler.added(m_resources[i], null); } } } /** * Remove a Resource consumer. * @param handler */ public void remove(ResourceHandler handler) { System.out.println("ResourceProvider.removeResourceHandler " + handler); Filter filter; synchronized (m_handlers) { filter = (Filter) m_handlers.remove(handler); } removeResources(handler, filter); } @SuppressWarnings("unchecked") private void removeResources(ResourceHandler handler, Filter filter) { for (int i = 0; i < m_resources.length; i++) { if (filter == null || filter.match((Dictionary<String, ?>) ResourceUtil.createProperties(m_resources[i]))) { handler.removed(m_resources[i], null); } } } /** * Our component is being destroyed: notify all our registered Resource consumers that we don't * provide our Resources anymore. */ @SuppressWarnings("unchecked") @Destroy public void destroy() { Entry[] handlers; synchronized (m_handlers) { handlers = (Entry[]) m_handlers.entrySet().toArray(new Entry[m_handlers.size()]); } for (int i = 0; i < handlers.length; i++) { removeResources((ResourceHandler) handlers[i].getKey(), (Filter) handlers[i].getValue()); } } } /** * Our ServiceInterface provider, which service is activated by a ResourceAdapter. */ @ResourceAdapterService(filter = "(&(path=/path/to/test1.txt)(host=localhost))", properties = {@Property(name = "foo", value = "bar")}, propagate = true) public static class ServiceProvider implements ServiceInterface { // Injected by reflection URL m_resource; @ServiceDependency(filter = "(name=" + ENSURE_ADAPTER + ")") Ensure m_sequencer; // Check auto config injections @Inject BundleContext m_bc; BundleContext m_bcNotInjected; @Inject DependencyManager m_dm; DependencyManager m_dmNotInjected; @Inject org.apache.felix.dm.Component m_component; org.apache.felix.dm.Component m_componentNotInjected; public void run() { checkInjectedFields(); Assert.assertNotNull("Resource has not been injected in the adapter", m_resource); Assert.assertEquals("ServiceProvider did not get expected resource", "file://localhost/path/to/test1.txt", m_resource.toString()); m_sequencer.step(2); } private void checkInjectedFields() { if (m_bc == null) { m_sequencer.throwable(new Exception("Bundle Context not injected")); return; } if (m_bcNotInjected != null) { m_sequencer.throwable(new Exception("Bundle Context must not be injected")); return; } if (m_dm == null) { m_sequencer.throwable(new Exception("DependencyManager not injected")); return; } if (m_dmNotInjected != null) { m_sequencer.throwable(new Exception("DependencyManager must not be injected")); return; } if (m_component == null) { m_sequencer.throwable(new Exception("Component not injected")); return; } if (m_componentNotInjected != null) { m_sequencer.throwable(new Exception("Component must not be injected")); return; } } } /** * A Component with a dependency over the ServiceInterface, which is actually provided * by a ResourceAdapter. */ @Component public static class ServiceConsumer { @ServiceDependency ServiceInterface m_serviceInterface; @ServiceDependency(filter = "(name=" + ENSURE_ADAPTER + ")") Ensure m_sequencer; @Start void start() { m_sequencer.step(1); m_serviceInterface.run(); } } }