/*
* 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.aries.jndi;
import java.util.Arrays;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.naming.directory.Attributes;
import javax.naming.spi.DirObjectFactory;
import javax.naming.spi.ObjectFactory;
import javax.naming.spi.ObjectFactoryBuilder;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
public class DirObjectFactoryHelper extends ObjectFactoryHelper implements DirObjectFactory {
public DirObjectFactoryHelper(BundleContext defaultContext, BundleContext callerContext) {
super(defaultContext, callerContext);
}
public Object getObjectInstance(Object obj,
Name name,
Context nameCtx,
Hashtable<?, ?> environment,
Attributes attrs) throws Exception {
// Step 1
if (obj instanceof Referenceable) {
obj = ((Referenceable) obj).getReference();
}
Object result = obj;
// Step 2
if (obj instanceof Reference) {
Reference ref = (Reference) obj;
String className = ref.getFactoryClassName();
if (className != null) {
// Step 3
result = getObjectInstanceUsingClassName(obj, className, obj, name, nameCtx, environment, attrs);
}
}
// Step 4
if (result == null || result == obj) {
result = getObjectInstanceUsingObjectFactoryBuilders(obj, name, nameCtx, environment, attrs);
}
// Step 5
if (result == null || result == obj) {
if ((obj instanceof Reference && ((Reference) obj).getFactoryClassName() == null) ||
!(obj instanceof Reference)) {
result = getObjectInstanceUsingObjectFactories(obj, name, nameCtx, environment, attrs);
}
}
// Extra, non-standard, bonus step. If javax.naming.OBJECT_FACTORIES is set as
// a property in the environment, use its value to construct additional object factories.
// Added under Aries-822, with reference
// to https://www.osgi.org/bugzilla/show_bug.cgi?id=138
if (result == null || result == obj) {
result = getObjectInstanceViaContextDotObjectFactories(obj, name, nameCtx, environment, attrs);
}
return (result == null) ? obj : result;
}
private Object getObjectInstanceUsingObjectFactories(Object obj,
Name name,
Context nameCtx,
Hashtable<?, ?> environment,
Attributes attrs)
throws Exception {
Object result = null;
ServiceReference[] refs = Utils.getReferencesPrivileged(callerContext, DirObjectFactory.class);
if (refs != null) {
Arrays.sort(refs, Utils.SERVICE_REFERENCE_COMPARATOR);
for (ServiceReference ref : refs) {
if (canCallObjectFactory(obj, ref)) {
DirObjectFactory factory = (DirObjectFactory) Utils.getServicePrivileged(callerContext, ref);
try {
result = factory.getObjectInstance(obj, name, nameCtx, environment, attrs);
} finally {
callerContext.ungetService(ref);
}
// if the result comes back and is not null and not the reference
// object then we should return the result, so break out of the
// loop we are in.
if (result != null && result != obj) {
break;
}
}
}
}
if (result == null) {
result = getObjectInstanceUsingObjectFactories(obj, name, nameCtx, environment);
}
return (result == null) ? obj : result;
}
private boolean canCallObjectFactory(Object obj, ServiceReference ref)
{
if (obj instanceof Reference) return true;
Object prop = ref.getProperty("aries.object.factory.requires.reference");
if (prop == null) return true;
if (prop instanceof Boolean) return !!!(Boolean) prop; // if set to true we don't call.
return true;
}
private Object getObjectInstanceUsingClassName(Object reference,
String className,
Object obj,
Name name,
Context nameCtx,
Hashtable<?, ?> environment,
Attributes attrs)
throws Exception {
Tuple<ServiceReference, ObjectFactory> tuple = ObjectFactoryHelper.findObjectFactoryByClassName(defaultContext, className);
Object result = null;
if (tuple.second != null) {
try {
result = ((DirObjectFactory) tuple.second).getObjectInstance(reference, name, nameCtx, environment, attrs);
} finally {
defaultContext.ungetService(tuple.first);
}
}
return (result == null) ? obj : result;
}
private Object getObjectInstanceUsingObjectFactoryBuilders(Object obj,
Name name,
Context nameCtx,
Hashtable<?, ?> environment,
Attributes attrs)
throws Exception {
ObjectFactory factory = null;
ServiceReference[] refs = Utils.getReferencesPrivileged(callerContext, ObjectFactoryBuilder.class);
if (refs != null) {
Arrays.sort(refs, Utils.SERVICE_REFERENCE_COMPARATOR);
for (ServiceReference ref : refs) {
ObjectFactoryBuilder builder = (ObjectFactoryBuilder) Utils.getServicePrivileged(callerContext, ref);
try {
factory = builder.createObjectFactory(obj, environment);
} catch (NamingException e) {
// TODO: log it
} finally {
callerContext.ungetService(ref);
}
if (factory != null) {
break;
}
}
}
Object result = null;
if (factory != null) {
if (factory instanceof DirObjectFactory) {
result = ((DirObjectFactory) factory).getObjectInstance(obj, name, nameCtx, environment, attrs);
} else {
result = factory.getObjectInstance(obj, name, nameCtx, environment);
}
}
return (result == null) ? obj : result;
}
}