package org.oddjob.framework;
import java.util.LinkedHashMap;
import java.util.Map;
import org.oddjob.arooa.registry.ServiceProvider;
import org.oddjob.arooa.registry.Services;
import org.oddjob.arooa.types.IsType;
/**
* @oddjob.description Allows objects to be registered that will
* automatically be injected into subsequent components that
* are configured for automatic dependency injection.
* <p>
*
* @oddjob.example
*
* The Development guide has numerous examples using this job.
*
*
* @author rob
*
*/
public class ServicesJob extends SimpleJob
implements ServiceProvider {
/**
* @oddjob.property registeredServices
* @oddjob.description Service definitions. These are simple beans
* that define the services being registered. Because of their
* simplicity they do not have their own type and can be specified
* using the {@link IsType}.
* <p>
* The properties of the service definition beans are:
* <dl>
* <dt>service</dt>
* <dd>The service object being registered.</dd>
*
* <dt>qualifier</dt>
* <dd>A qualified that provides extra information for the
* type of service.</dd>
*
* <dt>intransigent</dt>
* <dd>Whether or not to supply a service if the qualifier does
* not match that which is required.</dd>
* </dl>
*
*
* @oddjob.required No, but pointless if missing.
*/
private final Map<String, ServiceDefinition> services =
new LinkedHashMap<String, ServiceDefinition>();
@Override
protected int execute() throws Throwable {
// Configuration starts the service
return 0;
}
@Override
protected void onReset() {
services.clear();
}
/**
* @oddjob.property services
* @oddjob.description Provide access to the registered services.
* <p>
* Services
* are registered by name using object {@code toString} and then if qualified
* ';' and the qualifier. If this job has an id {@code my-services} and
* the service has a toString of {@code MyCafe} and it is qualified with qualifier
* {@code Vegetarian} then it could be referenced as:
* <pre>
* ${my-services.services.service(MyCafe;Vegetarian)}
* </pre>
*/
@Override
public Services getServices() {
return new Services() {
@Override
public Object getService(String serviceName)
throws IllegalArgumentException {
ServiceDefinition def = services.get(serviceName);
if (def == null) {
return null;
}
return def.getService();
}
@Override
public String serviceNameFor(Class<?> theClass, String flavour) {
String best = null;
for (Map.Entry<String, ServiceDefinition> entry :
services.entrySet()) {
ServiceDefinition def = entry.getValue();
if (theClass.isInstance(def.getService())) {
if (flavour == null ) {
if (def.getQualifier() == null ||
!def.isIntransigent()) {
return entry.getKey();
}
else {
continue;
}
}
if (flavour.equals(def.getQualifier())) {
return entry.getKey();
}
if (!def.isIntransigent()) {
best = entry.getKey();
}
}
}
return best;
}
@Override
public String toString() {
return "Registered Services: " + services.size();
}
};
}
public void setRegisteredServices(int index, ServiceDefinition serviceDef) {
if (serviceDef == null) {
return;
}
Object service = serviceDef.getService();
if (service == null) {
throw new NullPointerException(
"Service in service definition is null");
}
Object qualifier = serviceDef.getQualifier();
String serviceName = service.toString() +
(qualifier == null ? "" : ";" + qualifier.toString());
logger().info("Registered service " + serviceName +
" for types assignable from " + service.getClass().getName());
services.put(serviceName, serviceDef);
}
/** Definition of a service. */
public static class ServiceDefinition {
private Object service;
private Object qualifier;
private boolean intransigent;
public Object getService() {
return service;
}
public void setService(Object service) {
this.service = service;
}
public Object getQualifier() {
return qualifier;
}
public void setQualifier(Object qualifier) {
this.qualifier = qualifier;
}
public boolean isIntransigent() {
return intransigent;
}
public void setIntransigent(boolean constrained) {
this.intransigent = constrained;
}
}
}