/**
* Copyright OPS4J
*
* Licensed 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.
*
* @author nmw
* @version $Id: $Id
*/
package org.ops4j.pax.wicket.spi.support;
import java.util.Map;
import org.ops4j.pax.wicket.spi.ProxyTarget;
import org.ops4j.pax.wicket.spi.ProxyTargetLocator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
public abstract class AbstractProxyTargetLocator<Container> implements ProxyTargetLocator {
private static final long serialVersionUID = 1L;
protected Class<?> beanType;
protected Map<String, String> overwrites;
private final Class<?> parent;
private final BundleContext bundleContext;
private final String beanName;
/**
* <p>Constructor for AbstractProxyTargetLocator.</p>
*
* @param bundleContext a {@link org.osgi.framework.BundleContext} object.
* @param beanName a {@link java.lang.String} object.
* @param beanType a {@link java.lang.Class} object.
* @param parent a {@link java.lang.Class} object.
* @param overwrites a {@link java.util.Map} object.
*/
public AbstractProxyTargetLocator(BundleContext bundleContext, String beanName, Class<?> beanType,
Class<?> parent, Map<String, String> overwrites) {
this.bundleContext = bundleContext;
this.beanName = beanName;
this.beanType = beanType;
this.parent = parent;
this.overwrites = overwrites;
}
/**
* <p>hasApplicationContext.</p>
*
* @return a boolean.
*/
public boolean hasApplicationContext() {
String filter = getApplicationContextFilter(bundleContext.getBundle().getSymbolicName());
ServiceReference<?>[] references = null;
try {
references = bundleContext.getServiceReferences(getContainerClass().getName(), filter);
} catch (InvalidSyntaxException e) {
throw new IllegalStateException("not possible", e);
}
return references != null && references.length != 0;
}
/**
* <p>Getter for the field <code>beanName</code>.</p>
*
* @return the current value of beanName
*/
public String getBeanName() {
return beanName;
}
/**
* <p>locateProxyTarget.</p>
*
* @return a {@link org.ops4j.pax.wicket.spi.ProxyTarget} object.
*/
public ProxyTarget locateProxyTarget() {
if (bundleContext == null) {
throw new IllegalStateException("Bundle context is not allowed to be null");
}
ClassLoader oldClassloader = Thread.currentThread().getContextClassLoader();
String filter = getApplicationContextFilter(bundleContext.getBundle().getSymbolicName());
ServiceReference<?>[] references = null;
try {
references = bundleContext.getServiceReferences(getContainerClass().getName(), filter);
} catch (InvalidSyntaxException e) {
throw new IllegalStateException("not possible", e);
}
if (references == null || references.length == 0) {
throw new IllegalStateException(String.format("Found zero service references for %s; this is not OK...",
bundleContext.getBundle().getSymbolicName()));
}
try {
Thread.currentThread().setContextClassLoader(parent.getClassLoader());
final BeanReactor<Container> strategy = createStrategy();
for (ServiceReference<?> serviceReference : references) {
@SuppressWarnings("unchecked")
final Container service = (Container) bundleContext.getService(serviceReference);
try {
if (!strategy.containsBean(service)) {
continue;
}
return new ProxyTarget() {
public Object getTarget() {
return strategy.createBean(service);
}
};
} finally {
bundleContext.ungetService(serviceReference);
}
}
} finally {
Thread.currentThread().setContextClassLoader(oldClassloader);
}
throw new IllegalStateException(String.format(
"Bundle %s can no longer attach bean %s with ID %s, class %s to page %s", bundleContext
.getBundle().getSymbolicName(), beanType.getName(), beanName, beanType.getName(),
parent.getName()));
}
/**
* <p>Getter for the field <code>parent</code>.</p>
*
* @return a {@link java.lang.Class} object.
*/
public Class<?> getParent() {
return parent;
}
/**
* <p>createStrategy.</p>
*
* @return a {@link org.ops4j.pax.wicket.spi.support.AbstractProxyTargetLocator.BeanReactor} object.
*/
protected abstract BeanReactor<Container> createStrategy();
/**
* <p>getApplicationContextFilter.</p>
*
* @param symbolicBundleName a {@link java.lang.String} object.
* @return a {@link java.lang.String} object.
*/
protected abstract String getApplicationContextFilter(String symbolicBundleName);
/**
* <p>getContainerClass.</p>
*
* @return a {@link java.lang.Class} object.
*/
protected abstract Class<? extends Container> getContainerClass();
protected static interface BeanReactor<Container> {
boolean containsBean(Container applicationContext);
Object createBean(Container applicationContext);
}
}