
org.distributeme.generator.ServerGenerator Maven / Gradle / Ivy
package org.distributeme.generator;
import com.sun.mirror.apt.Filer;
import com.sun.mirror.declaration.AnnotationMirror;
import com.sun.mirror.declaration.AnnotationValue;
import com.sun.mirror.declaration.TypeDeclaration;
import com.sun.tools.apt.mirror.declaration.AnnotationValueImpl;
import net.anotheria.anoprise.metafactory.Extension;
import net.anotheria.anoprise.metafactory.FactoryNotFoundException;
import net.anotheria.anoprise.metafactory.MetaFactory;
import net.anotheria.anoprise.metafactory.ServiceFactory;
import net.anotheria.util.IdCodeGenerator;
import net.anotheria.util.PidTools;
import org.distributeme.annotation.CombinedService;
import org.distributeme.annotation.DistributeMe;
import org.distributeme.annotation.DummyFactory;
import org.distributeme.annotation.Route;
import org.distributeme.annotation.RouteMe;
import org.distributeme.annotation.ServerListener;
import org.distributeme.annotation.SupportService;
import org.distributeme.core.RMIRegistryUtil;
import org.distributeme.core.RegistryLocation;
import org.distributeme.core.RegistryUtil;
import org.distributeme.core.ServerShutdownHook;
import org.distributeme.core.ServiceDescriptor;
import org.distributeme.core.SystemPropertyNames;
import org.distributeme.core.Verbosity;
import org.distributeme.core.conventions.SystemProperties;
import org.distributeme.core.lifecycle.LifecycleComponentImpl;
import org.distributeme.core.listener.ListenerRegistry;
import org.distributeme.core.listener.ServerLifecycleListener;
import org.distributeme.core.listener.ServerLifecycleListenerShutdownHook;
import org.distributeme.core.routing.RegistrationNameProvider;
import org.distributeme.core.routing.RoutingAware;
import org.distributeme.core.util.LocalServiceDescriptorStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
import java.io.IOException;
import java.io.PrintWriter;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.ExportException;
import java.rmi.server.UnicastRemoteObject;
import java.security.Permission;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Generator for RMI based server programm.
* @author lrosenberg
*/
public class ServerGenerator extends AbstractGenerator implements Generator{
private static final String[] SUPPORT_SERVICES_ONLY = {
"org.distributeme.support.lifecycle.generated.LifecycleSupportServer",
"org.distributeme.support.eventservice.generated.EventServiceRMIBridgeServer",
};
private static final String[] SUPPORT_SERVICES_WITH_AGENTS = {
"org.distributeme.support.lifecycle.generated.LifecycleSupportServer",
"org.distributeme.support.eventservice.generated.EventServiceRMIBridgeServer",
"org.distributeme.agents.transporter.generated.TransporterServer",
};
@Override
public void generate(TypeDeclaration type, Filer filer, Map options) throws IOException{
PrintWriter writer = filer.createSourceFile(getPackageName(type)+"."+getServerName(type));
setWriter(writer);
//meta servers rely on other skeletons and just starts them.
boolean combinedServer = type.getAnnotation(CombinedService.class)!=null;
writePackage(type);
writeAnalyzerComments(type);
emptyline();
writeImport(Logger.class);
writeImport(LoggerFactory.class);
writeImport(Marker.class);
writeImport(MarkerFactory.class);
writeImport(UnicastRemoteObject.class);
writeImport(Permission.class);
writeImport(LocateRegistry.class);
writeImport(Registry.class);
writeImport(RegistryUtil.class);
writeImport(RegistryLocation.class);
writeImport(ExportException.class);
writeImport(ServiceDescriptor.class);
writeImport(LocalServiceDescriptorStore.class);
writeImport("org.distributeme.core.ServiceDescriptor.Protocol");
writeImport(MetaFactory.class);
writeImport(FactoryNotFoundException.class);
writeImport(Extension.class);
writeImport(PidTools.class);
writeImport(IdCodeGenerator.class);
writeImport(RMIRegistryUtil.class);
writeImport(RemoteException.class);
writeImport(ServiceFactory.class);
writeImport(LifecycleComponentImpl.class);
writeImport(Verbosity.class);
writeImport(SystemPropertyNames.class);
writeImport(ServerShutdownHook.class);
writeImport(SystemProperties.class);
writeImport(List.class);
writeImport(RoutingAware.class);
emptyline();
DistributeMe annotation = type.getAnnotation(DistributeMe.class);
boolean supportService = type.getAnnotation(SupportService.class)!=null;
String [] SUPPORT_SERVICES = annotation.agentsSupport() ? SUPPORT_SERVICES_WITH_AGENTS : SUPPORT_SERVICES_ONLY;
if (!supportService){
for (String sService : SUPPORT_SERVICES){
writeImport(sService);
}
}
writeString("public class "+getServerName(type)+"{");
increaseIdent();
emptyline();
writeStatement("private static Logger log");
writeStatement("private static Marker FATAL = MarkerFactory.getMarker(\"FATAL\")");
emptyline();
//checking for support service.
if (!supportService){
//only support service gets a main method
writeString("public static void main(String a[]) throws Exception{");
increaseIdent();
writeString("if (System.getSecurityManager()==null)");
increaseIdent();
writeCommentLine("We allow all operations.");
writeString("System.setSecurityManager(new SecurityManager(){");
writeIncreasedString("public void checkPermission(Permission perm) { }");
writeStatement("})");
decreaseIdent();
writeString("try {");
increaseIdent();
writeStatement("init()");
writeCommentLine("Log current server PID (Process Id)");
writeStatement("PidTools.logPid()");
writeCommentLine("force verbosity to configure itself");
writeStatement("Verbosity.logServerSideExceptions()");
writeStatement("createSupportServicesAndRegisterLocally()");
if(!combinedServer){
writeStatement("createServiceAndRegisterLocally()");
}
if(combinedServer){
writeStatement("createCombinedServicesAndRegisterLocally()");
}
writeStatement("startService()");
writeStatement("notifyListenersAboutStart()");
//writeStatement("this(new "+type.getAnnotation(DistributeMe.class).implName()+"())");
decreaseIdent();
writeString("} catch (Throwable e) {");
increaseIdent();
writeStatement("log.error(FATAL, \"Unhandled exception caught\", e)");
writeStatement("System.err.println(e.getMessage())");
writeStatement("System.exit(-4)");
decreaseIdent();
writeString("}");
closeBlock("main");
emptyline();
}
if (supportService){
writeCommentLine("Support service have no main method");
}
List mirrors = findMirrors(type, ServerListener.class);
writeStatement("private static final List<"+ServerLifecycleListener.class.getName()+"> serverListeners = new "+ArrayList.class.getName()+"<"+ServerLifecycleListener.class.getName()+">("+(mirrors==null ? 0:mirrors.size())+")");
writeString("private static void notifyListenersAboutStart(){");
increaseIdent();
if (mirrors!=null && mirrors.size()>0){
writeCommentLine("compiled listeners");
for (AnnotationMirror mirror : mirrors){
writeString("try{");
increaseIdent();
writeStatement(ServerLifecycleListener.class.getName()+" listener = new "+findMethodValue(mirror, "listenerClass").getValue()+"()");
writeStatement("listener.afterStart()");
writeCommentLine("Only add successful listeners");
writeStatement("serverListeners.add(listener)");
decreaseIdent();
writeString("}catch(Exception e){");
writeIncreasedStatement("log.error("+quote("Couldn't initialize listener "+findMethodValue(mirror, "listenerClass").getValue())+", e)");
writeString("}");
}
//writeStatement("private static final "+ServerListener.class.getName()+" serverListeners = new "+ArrayList.class.getName()+"<"+ServerListener.class.getName()+">("+mirrors.size()+")");
emptyline();
}
writeCommentLine("configured listeners");
writeStatement("List<"+ServerLifecycleListener.class.getName()+"> configuredListeners = "+ListenerRegistry.class.getName()+".getInstance().getServerLifecycleListeners()");
writeString("if (configuredListeners!=null && configuredListeners.size()>0){");
increaseIdent();
writeString("for ("+ServerLifecycleListener.class.getName()+" listener : configuredListeners){");
increaseIdent();
writeString("try{");
increaseIdent();
writeStatement("listener.afterStart()");
decreaseIdent();
writeString("}catch(Exception e){");
writeIncreasedStatement("log.error("+quote("Couldn't call afterStart on listener ")+" + listener, e)");
writeString("}");
closeBlock("for");
closeBlock("if");
closeBlock("notifyListenersAboutStart");
emptyline();
writeString("public static void init() throws Exception{");
increaseIdent();
writeStatement("log = LoggerFactory.getLogger("+getServerName(type)+".class)");
writeCommentLine("// CUSTOM CODE STARTED");
String[] initCode = annotation.initcode();
for (String s : initCode){
writeString(s);
}
writeCommentLine("// CUSTOM CODE ENDED");
closeBlock("init");
emptyline();
if (!combinedServer){
//START METHOD createServiceAndRegisterLocally
writeCommentLine("Have to keep local reference to the rmiServant and skeleton to prevent gc removal");
writeStatement("private static "+getRemoteInterfaceName(type)+" skeleton = null");
writeStatement("private static "+getRemoteInterfaceName(type)+" rmiServant = null");
writeStatement("private static String serviceId = null");
emptyline();
writeString("public static void createServiceAndRegisterLocally() throws Exception{");
increaseIdent();
writeCommentLine("creating impl");
//old , direct instantiation writeStatement(type.getQualifiedName()+" impl = new "+type.getAnnotation(DistributeMe.class).factoryClassName()+"().create()");
AnnotationMirror annotationMirror = findMirror(type, DistributeMe.class);
if (annotationMirror==null)
throw new AssertionError("AnnotationMirror is null, which actually can't happen, since the annotation was previously found: "+annotation);
AnnotationValue factoryClazzValue = findMethodValue(annotationMirror, "factoryClazz");
String factoryClassName = getDefaultImplFactoryName(type);
String implClassName = type.getQualifiedName()+"Impl";
if (factoryClazzValue!=null && !(factoryClazzValue.getValue().equals(DummyFactory.class.getName()+".class"))){
writeCommentLine("Registering factory");
writeStatement("MetaFactory.addFactoryClass("+type+".class, Extension."+annotation.extension()+", "+factoryClazzValue.getValue()+".class)");
}else{
writeCommentLine("No factory specified");
if (initCode.length>0){
writeCommentLine("init code not empty, assuming it contains factory declaration");
}else{
//try autoresolve
writeString("try{");
increaseIdent();
writeStatement("Class> factoryClazz = (Class>)Class.forName("+quote(factoryClassName)+")");
writeStatement("MetaFactory.addFactoryClass("+type+".class, Extension."+annotation.extension()+", factoryClazz)");
decreaseIdent();
writeString("}catch(ClassNotFoundException factoryNotFound){");
increaseIdent();
writeString("try{");
increaseIdent();
writeCommentLine("Even more convenient - try to instantiate the implementation directly");
writeStatement("Class extends "+type.getQualifiedName()+"> implClazz = (Class extends "+type.getQualifiedName()+">)Class.forName("+quote(implClassName)+")");
writeStatement("MetaFactory.createOnTheFlyFactory("+type+".class, Extension."+annotation.extension()+", implClazz.newInstance())");
decreaseIdent();
writeString("}catch(ClassNotFoundException implNotFound){");
increaseIdent();
writeStatement("log.info("+quote("Giving up trying to find an impl instance, tried "+factoryClassName+" and "+implClassName+", expect start to fail since init code were empty too and no factory has been supplied explicitely")+")");
closeBlock("inner catch");
closeBlock("outer catch");
}
}
writeStatement(type.getQualifiedName()+" impl = null");
writeString("try{");
increaseIdent();
writeStatement("impl = MetaFactory.get(" + type.getQualifiedName() + ".class, Extension." + annotation.extension() + ")");
decreaseIdent();
writeString("}catch (FactoryNotFoundException factoryNotFound){");
writeIncreasedStatement("throw new AssertionError(" + quote("Un- or mis-configured, can't instantiate service instance for " + type.getQualifiedName() + " tried initcode, submitted factory, autoguessed factory (" + factoryClassName + ") and impl class (" + implClassName + ")") + ")");
writeString("}");
writeStatement("skeleton = new " + getSkeletonName(type) + "(impl)");
writeStatement("rmiServant = (" + getRemoteInterfaceName(type) + ") UnicastRemoteObject.exportObject(skeleton, SystemProperties.SERVICE_BINDING_PORT.getAsInt())");
writeStatement("serviceId = "+getConstantsName(type)+".getServiceId()");
writeCommentLine("Save original serviceId for later RoutingAware call");
writeStatement("String definedServiceId = serviceId");
emptyline();
//determine whether we have a custom registration name.
if (type.getAnnotation(RouteMe.class)!=null){
emptyline();
writeCommentLine("Customizing registration name");
AnnotationMirror routeMe = findMirror(type, RouteMe.class);
AnnotationValue registrationNameProviderClazzValue = findMethodValue(routeMe, "providerClass");
AnnotationValue registrationNameProviderParameterValue = findMethodValue(routeMe, "providerParameter");
writeStatement(RegistrationNameProvider.class.getName()+" nameProvider = new "+registrationNameProviderClazzValue.getValue()+"()");
writeStatement("nameProvider.customize("+quote(registrationNameProviderParameterValue.getValue())+")");
writeStatement("serviceId = nameProvider.getRegistrationName(serviceId)");
emptyline();
}
//determine whether we have a registration name provider
writeStatement("String regNameProviderClass = System.getProperty(SystemPropertyNames.REGISTRATION_NAME_PROVIDER)");
writeString("if (regNameProviderClass!=null){");
increaseIdent();
writeStatement(RegistrationNameProvider.class.getName()+" suppliedNameProvider = ("+RegistrationNameProvider.class.getName()+")Class.forName(regNameProviderClass).newInstance()");
writeStatement("serviceId = suppliedNameProvider.getRegistrationName(serviceId)");
closeBlock("if (regNameProviderClass!=null)");
emptyline();
writeStatement("log.info("+quote("Getting local registry")+")");
writeStatement("Registry registry = null");
openTry();
writeStatement("registry = RMIRegistryUtil.findOrCreateRegistry()");
decreaseIdent();
writeString("}catch(RemoteException e){");
increaseIdent();
writeStatement("log.error(FATAL, "+quote("Couldn't obtain free port for a local rmi registry")+", e)");
writeStatement("System.err.println("+quote("Couldn't obtain a free port for local rmi registry")+")");
writeStatement("System.exit(-1)");
closeBlock();
emptyline();
writeStatement("log.info(" + quote("Registering ") + "+serviceId+" + quote(" locally.") + ")");
emptyline();
openTry();
writeStatement("registry.rebind(serviceId, rmiServant)");
decreaseIdent();
writeStatement("}catch(Exception e){");
increaseIdent();
writeStatement("log.error(FATAL, "+quote("Couldn't rebind myself at the local registry")+", e)");
writeStatement("System.err.println("+quote("Couldn't rebind myself at the local registry")+")");
writeStatement("e.printStackTrace()");
writeStatement("System.exit(-2)");
closeBlock("local registry bind.");
emptyline();
//ROUTING AWARE-NESS.
AnnotationMirror annotationMirrorRoute = findMirror(type, Route.class);
if (annotationMirror!=null){
AnnotationValue routerParameter = findMethodValue(annotationMirror, "routerParameter");
AnnotationValue configurationName = findMethodValue(annotationMirror, "configurationName");
//after registration, if service is RoutingAware we should notify it about its name.
//of course it only makes sense if the service had Route annotation.
writeString("if (impl instanceof RoutingAware){");
System.out.println("RP: " + routerParameter);
System.out.println("CN: "+configurationName);
increaseIdent();
writeStatement("((RoutingAware)impl).notifyServiceId(definedServiceId, serviceId, "
+ (routerParameter == null ? "null" : quote(routerParameter.getValue()))
+ ", "
+ (configurationName == null ? "null" : quote(configurationName.getValue()))
+ ") ");
closeBlock("/if impl RoutingAware");
}
//finally locally register service
if (!supportService){
writeStatement("LifecycleComponentImpl.INSTANCE.registerPublicService(serviceId, skeleton)");
}
closeBlock();
emptyline();
}
//combined server have no own descriptors.
if (!combinedServer){
writeString("public static ServiceDescriptor createDescriptor(String instanceId) throws Exception{");
String descriptorCall = "RegistryUtil.createLocalServiceDescription("+
"Protocol.RMI, "+
" serviceId,"+
" instanceId,"+
" RMIRegistryUtil.getRmiRegistryPort())";
increaseIdent();
writeStatement("return "+descriptorCall);
closeBlock();
}
//METHOD startService
writeString("public static void startService() throws Exception{");
increaseIdent();
// writeStatement("String serviceId = "+getConstantsName(type)+".getServiceId()");
writeStatement("String instanceId = IdCodeGenerator.generateCode(10)");
if(!combinedServer){
writeStatement("boolean registerCentrally = !SystemProperties.SKIP_CENTRAL_REGISTRY.getAsBoolean()");
writeString("if (registerCentrally){");
increaseIdent();
writeStatement("ServiceDescriptor descriptor = createDescriptor(instanceId)");
writeStatement("LocalServiceDescriptorStore.getInstance().addServiceDescriptor(descriptor)");
emptyline();
writeString("if (!RegistryUtil.bind(descriptor)){");
increaseIdent();
writeStatement("log.error(FATAL, "+quote("Couldn't bind myself to the central registry at ")+"+RegistryUtil.describeRegistry())");
writeStatement("System.err.println("+quote("Couldn't bind myself at the central registry at ")+"+RegistryUtil.describeRegistry())");
writeStatement("System.exit(-3)");
closeBlock("central registry bind");
writeStatement("Runtime.getRuntime().addShutdownHook(new ServerShutdownHook(descriptor))");
emptyline();
decreaseIdent();
writeString("}else{");
writeIncreasedStatement("System.out.println("+quote("skipping registration for ")+"+serviceId"+")");
writeString("}");
writeStatement("System.out.println("+quote("Server ")+"+serviceId+"+quote(" is up and ready.")+")");
}
if(combinedServer){
List serviceNames = getCombinedServicesNames(type);
for (String service : serviceNames){
String descriptorVariableName = getServerName(service).toLowerCase()+"Descriptor";
String serviceServerClassName = getFullyQualifiedServerName(service);
writeStatement("ServiceDescriptor "+descriptorVariableName+" = "+serviceServerClassName+".createDescriptor(instanceId)");
writeStatement("LocalServiceDescriptorStore.getInstance().addServiceDescriptor("+descriptorVariableName+")");
emptyline();
writeString("if (!RegistryUtil.bind("+descriptorVariableName+")){");
increaseIdent();
writeStatement("log.error(FATAL, "+quote("Couldn't bind ")+"+"+descriptorVariableName+"+"+quote(" to the central registry at ")+"+RegistryUtil.describeRegistry())");
writeStatement("System.err.println("+quote("Couldn't bind ")+"+"+descriptorVariableName+"+"+quote(" at the central registry at ")+"+RegistryUtil.describeRegistry())");
writeStatement("System.exit(-3)");
closeBlock("central registry bind");
writeStatement("Runtime.getRuntime().addShutdownHook(new ServerShutdownHook("+descriptorVariableName+"))");
emptyline();
writeStatement("System.out.println("+quote("Server ")+"+"+descriptorVariableName+".getServiceId()+"+quote(" is up and ready.")+")");
}
}
//note, this shutdown hook will be activated AFTER de-registration hook.
writeStatement("Runtime.getRuntime().addShutdownHook(new "+ServerLifecycleListenerShutdownHook.class.getName()+"(serverListeners))");
closeBlock("startService");
if (!supportService){
emptyline();
//METHOD createSupportServicesAndRegisterLocally
writeString("public static void createSupportServicesAndRegisterLocally() throws Exception{");
increaseIdent();
for (String s : SUPPORT_SERVICES){
writeStatement(s+".init()");
writeStatement(s+".createServiceAndRegisterLocally()");
}
closeBlock("createSupportServicesAndRegisterLocally");
emptyline();
}
if (combinedServer){
emptyline();
writeString("public static void createCombinedServicesAndRegisterLocally() throws Exception{");
increaseIdent();
List targetServicesNames = getCombinedServicesNames(type);
for (String service : targetServicesNames){
writeStatement(getFullyQualifiedServerName(service)+".init()");
writeStatement(getFullyQualifiedServerName(service)+".createServiceAndRegisterLocally()");
}
// for (String s : SUPPORT_SERVICES){
// writeStatement(s+".init()");
// writeStatement(s+".createServiceAndRegisterLocally()");
// }
closeBlock("createCombinedServicesAndRegisterLocally");
emptyline();
}
closeBlock();
writer.flush();
writer.close();
}
private List getCombinedServicesNames(TypeDeclaration type){
AnnotationMirror ann = findMirror(type, CombinedService.class);
AnnotationValue val = findMethodValue(ann, "services");
@SuppressWarnings("unchecked")ArrayList values = (ArrayList)val.getValue();
ArrayList ret = new ArrayList();
for (AnnotationValueImpl o : values){
ret.add(o.getValue().toString());
}
return ret;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy