blob: ca36c955c0abc00160212e369002ddef6f012708 [file] [log] [blame]
/*
* 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";
}
}