/* * 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; import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.util.Dictionary; import java.util.Enumeration; import java.util.Hashtable; import org.apache.felix.dm.Component; import org.apache.felix.dm.ComponentDependencyDeclaration; import org.apache.felix.dm.ResourceDependency; import org.apache.felix.dm.ResourceHandler; import org.apache.felix.dm.context.AbstractDependency; import org.apache.felix.dm.context.DependencyContext; import org.apache.felix.dm.context.Event; import org.apache.felix.dm.context.EventType; import org.osgi.framework.ServiceRegistration; /** * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> */ public class ResourceDependencyImpl extends AbstractDependency<ResourceDependency> implements ResourceDependency, ResourceHandler, ComponentDependencyDeclaration { private volatile ServiceRegistration<?> m_registration; private volatile String m_resourceFilter; private volatile URL m_trackedResource; public ResourceDependencyImpl() { } public ResourceDependencyImpl(ResourceDependencyImpl prototype) { super(prototype); m_resourceFilter = prototype.m_resourceFilter; m_trackedResource = prototype.m_trackedResource; } @Override public DependencyContext createCopy() { return new ResourceDependencyImpl(this); } @Override public void start() { Dictionary<String, Object> props = null; if (m_trackedResource != null) { props = new Hashtable<>(); props.put(ResourceHandler.URL, m_trackedResource); } else { if (m_resourceFilter != null) { props = new Hashtable<>(); props.put(ResourceHandler.FILTER, m_resourceFilter); } } m_registration = m_component.getBundleContext().registerService(ResourceHandler.class.getName(), this, props); super.start(); } @Override public void stop() { m_registration.unregister(); m_registration = null; super.stop(); } public void added(URL resource) { if (m_trackedResource == null || m_trackedResource.equals(resource)) { getComponentContext().handleEvent(this, EventType.ADDED, new ResourceEventImpl(resource, null)); } } public void added(URL resource, Dictionary<?, ?> resourceProperties) { if (m_trackedResource == null || m_trackedResource.equals(resource)) { getComponentContext().handleEvent(this, EventType.ADDED, new ResourceEventImpl(resource, resourceProperties)); } } public void changed(URL resource) { if (m_trackedResource == null || m_trackedResource.equals(resource)) { m_component.handleEvent(this, EventType.CHANGED, new ResourceEventImpl(resource, null)); } } public void changed(URL resource, Dictionary<?, ?> resourceProperties) { if (m_trackedResource == null || m_trackedResource.equals(resource)) { m_component.handleEvent(this, EventType.CHANGED, new ResourceEventImpl(resource, resourceProperties)); } } public void removed(URL resource) { if (m_trackedResource == null || m_trackedResource.equals(resource)) { m_component.handleEvent(this, EventType.REMOVED, new ResourceEventImpl(resource, null)); } } public void removed(URL resource, Dictionary<?, ?> resourceProperties) { if (m_trackedResource == null || m_trackedResource.equals(resource)) { m_component.handleEvent(this, EventType.REMOVED, new ResourceEventImpl(resource, resourceProperties)); } } @Override public void invokeCallback(EventType type, Event ... e) { switch (type) { case ADDED: if (m_add != null) { invoke(m_add, e[0]); } break; case CHANGED: if (m_change != null) { invoke (m_change, e[0]); } break; case REMOVED: if (m_remove != null) { invoke (m_remove, e[0]); } break; default: break; } } private void invoke(String method, Event e) { ResourceEventImpl re = (ResourceEventImpl) e; URL serviceInstance = re.getResource(); Dictionary<?,?> resourceProperties = re.getProperties(); m_component.invokeCallbackMethod(getInstances(), method, new Class[][] { { Component.class, URL.class, Dictionary.class }, { Component.class, URL.class }, { Component.class }, { URL.class, Dictionary.class }, { URL.class }, { Object.class }, {}}, new Object[][] { { m_component, serviceInstance, resourceProperties }, { m_component, serviceInstance }, { m_component }, { serviceInstance, resourceProperties }, { serviceInstance }, { serviceInstance }, {}} ); } public ResourceDependency setResource(URL resource) { m_trackedResource = resource; return this; } public ResourceDependency setFilter(String resourceFilter) { ensureNotActive(); m_resourceFilter = resourceFilter; return this; } public ResourceDependency setFilter(String resourceFilter, String resourcePropertiesFilter) { ensureNotActive(); m_resourceFilter = resourceFilter; return this; } @Override public Class<?> getAutoConfigType() { return URL.class; } @SuppressWarnings("unchecked") public Dictionary<String, Object> getProperties() { ResourceEventImpl re = (ResourceEventImpl) m_component.getDependencyEvent(this); if (re != null) { URL resource = re.getResource(); Dictionary<String, Object> resourceProperties = re.getProperties(); if (m_propagateCallbackInstance != null && m_propagateCallbackMethod != null) { try { CallbackTypeDef callbackInfo = new CallbackTypeDef(URL.class, resource); return (Dictionary<String, Object>) InvocationUtil.invokeCallbackMethod(m_propagateCallbackInstance, m_propagateCallbackMethod, callbackInfo.m_sigs, callbackInfo.m_args); } catch (InvocationTargetException e) { m_component.getLogger().warn("Exception while invoking callback method", e.getCause()); } catch (Throwable e) { m_component.getLogger().warn("Exception while trying to invoke callback method", e); } throw new IllegalStateException("Could not invoke callback"); } else { Hashtable<String, Object> props = new Hashtable<>(); props.put(ResourceHandler.HOST, resource.getHost()); props.put(ResourceHandler.PATH, resource.getPath()); props.put(ResourceHandler.PROTOCOL, resource.getProtocol()); props.put(ResourceHandler.PORT, Integer.toString(resource.getPort())); // add the custom resource properties if (resourceProperties != null) { Enumeration<String> properyKeysEnum = resourceProperties.keys(); while (properyKeysEnum.hasMoreElements()) { String key = properyKeysEnum.nextElement(); if (!key.equals(ResourceHandler.HOST) && !key.equals(ResourceHandler.PATH) && !key.equals(ResourceHandler.PROTOCOL) && !key.equals(ResourceHandler.PORT)) { props.put(key, resourceProperties.get(key).toString()); } else { m_component.getLogger().warn( "Custom resource property is overlapping with the default resource property for key: %s", key); } } } return props; } } else { throw new IllegalStateException("cannot find resource"); } } @Override public String getName() { StringBuilder sb = new StringBuilder(); if (m_trackedResource != null) { sb.append(m_trackedResource.toString()); } if (m_resourceFilter != null) { sb.append(m_resourceFilter); } return sb.toString(); } @Override public String getSimpleName() { return m_trackedResource != null ? m_trackedResource.toString() : null; } @Override public String getFilter() { return m_resourceFilter; } @Override public String getType() { return "resource"; } }