All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nuiton.topia.service.TopiaApplicationServiceFactory Maven / Gradle / Ivy

There is a newer version: 2.3.1
Show newest version
/* *##% 
 * ToPIA :: SOA
 * Copyright (C) 2004 - 2009 CodeLutin
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * ##%*/

/**
 * 
 */
package org.nuiton.topia.service;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuiton.topia.TopiaContext;
import org.nuiton.topia.TopiaException;
import org.nuiton.topia.TopiaNotFoundException;
import org.nuiton.topia.framework.TopiaUtil;
import org.nuiton.topia.service.clients.RMIProxy;
import org.nuiton.topia.service.clients.SOAPProxy;
import org.nuiton.topia.service.clients.XMLRPCProxy;

import java.lang.reflect.Proxy;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

/**
 * TopiaServiceFactory.java
 * 
 * Classe utilisee pour charger les services.
 * 
 * Deux utilisations possibles :
 * 
  • client: pour avoir une interface sur un service local ou distant *
  • serveur: pour avoir un service local au serveur * * Sert aussi au serveur pour declarer des services * * @author chatellier * @version $Revision: 1715 $ * * Last update : $Date: 2009-12-15 01:26:16 +0100 (mar. 15 déc. 2009) $ By : $Author: tchemit $ */ public class TopiaApplicationServiceFactory { /** Fichier de configuration par defaut */ public static final String DEFAULT_CONFIG_PROPERTIES = "TopiaContextImpl.properties"; /** Nom de la propriete de definition des services utilises */ public static final String TOPIA_APPLICATION_SERVICE_BEGIN = "topia.application.service."; /** Nom de la propriete de definition des services fournit */ public static final String TOPIA_APPLICATION_PROVIDE_BEGIN = "topia.application.provide."; /** Nom de la propriete de definition des ports suivant les protocoles */ public static final String TOPIA_APPLICATION_SERVER_PORT_BEGIN = "topia.application.server.port."; /** * Nom du dossier ou sont generer certains fichiers (doit etre dans le * classpath ) */ public static String TOPIA_GENERATION_DIRECTORY = "topiagen"; /** Fichier de configuration */ protected static Properties config; /** Dispatcher (servers) */ protected static final TopiaServiceProvider mainDispatcher = new TopiaServiceProvider(); /** * Stockage des services deja instancies */ private static Map, TopiaApplicationService> mapServiceCache = new HashMap, TopiaApplicationService>(); /** Logger (common logging) */ private static final Log log = LogFactory .getLog(TopiaApplicationServiceFactory.class); protected static TopiaContext defaultServiceContext; /** * Retourne la configuration. Charge le fichier s'il n'a pas deja ete * charge. * * @throws TopiaNotFoundException * si le fichier de configuration ne peut pas etre charge * @return la configuration (et la charge si cela n'est pas déjà fait) */ static Properties getConfiguration() throws TopiaNotFoundException { if (config == null) { config = TopiaUtil.getProperties(DEFAULT_CONFIG_PROPERTIES); } return config; } /** * Charge et lance tous les services contenus dans le fichier de * configuration * * @param config * les proprietes du fichier de configuration * @param context * le contexte pere des contextes fournis aux services * @throws TopiaException if any pb with topia */ public static void loadServices(Properties config, TopiaContext context) throws TopiaException { if (context == null) { throw new NullPointerException( "I need a valid TopiaContext to initialise application services"); } defaultServiceContext = context; // lecture du fichier de configuration if (config == null) { try { config = getConfiguration(); } catch (TopiaNotFoundException e) { throw new TopiaNotFoundException( "Can't find configuration file " + DEFAULT_CONFIG_PROPERTIES); } } // pour chaque service applicatif Set keySet = config.keySet(); for (Object key : keySet) { if (key.toString().startsWith(TOPIA_APPLICATION_PROVIDE_BEGIN)) { // convertir l'URI pour recuperer les parametres String protos = config.getProperty(key.toString()); String serviceClassName = ((String) key).replace( TOPIA_APPLICATION_PROVIDE_BEGIN, ""); // lance pour chaque protocole String[] tabProtos = protos.split(","); for (String proto : tabProtos) { // instancier puis lancer le service Protocol protocol = Protocol.valueOf(proto.trim().replace( '-', '_').toUpperCase()); // read and set server port if (config.get(TOPIA_APPLICATION_SERVER_PORT_BEGIN + proto) != null) { Integer port = null; try { port = Integer.valueOf((String) config .get(TOPIA_APPLICATION_SERVER_PORT_BEGIN + proto)); } catch (NumberFormatException e) { log.warn("Can't convert " + proto + " server port to integer", e); } mainDispatcher.setProtocolPort(protocol, port); } try { Class serviceInterface = Class.forName(serviceClassName); Class serviceImplement = Class.forName(serviceClassName + "Impl"); try { Object newInstance = serviceImplement.newInstance(); TopiaApplicationService service = (TopiaApplicationService) newInstance; TopiaContext serviceContext = context .beginTransaction(); service.init(serviceContext); addService(serviceInterface, service, protocol); } catch (InstantiationException e) { throw new TopiaException( "Can't instanciate service class " + serviceImplement); } catch (IllegalAccessException e) { throw new TopiaException( "Can't access to service class " + serviceImplement); } log.info("service " + serviceClassName + " added for protocol " + proto); } catch (ClassNotFoundException e) { log.error("Class not found for " + serviceClassName, e); } } } } } /** * Fournit une interface sur un service en l'implementant comme definit dans * la configuration. * * Configuration (TopiaApplicationServices.properties par defaut) : * topia.application.service.fqn=local://fqnImpl/#new * topia.application.service.fqn=local://fqnImpl * topia.application.service.fqn=rmi://127.0.0.1:1099 * topia.application.service.fqn=xmlrpc://127.0.0.1:9090 ... * * @param * l'interface doit etendre TopiaApplicationService * @param serviceclazz * l'interface du service * @return l'implementation du service ou null si le service ne * peut etre charge * @see TopiaApplicationService * @throws TopiaNotFoundException * si le fichier de configuration n'existe pas * @throws TopiaException * si le service ne peut pas etre charge */ public static E getService( Class serviceclazz) throws TopiaNotFoundException, TopiaException { // l'implementation a retourner E serviceimpl = (E) mapServiceCache.get(serviceclazz); // s'il etait dans le cache on le retourne directement // dans le cas "#new" il n'est jamais dans le cache, donc recree if (serviceimpl != null) { return serviceimpl; } // configuration Properties config = getConfiguration(); // recherche du service String serviceUrl = (String) config.get(TOPIA_APPLICATION_SERVICE_BEGIN + serviceclazz.getCanonicalName()); if (serviceUrl == null) { log.error("Properties '" + TOPIA_APPLICATION_SERVICE_BEGIN + serviceclazz.getCanonicalName() + "' not found in configuration"); throw new TopiaNotFoundException("Service '" + serviceclazz.getCanonicalName() + "' not definided in configuration"); } else { try { // conversion de l'URI URI uriService = new URI(serviceUrl); String protocole = uriService.getScheme(); String host = uriService.getHost(); String fragment = uriService.getFragment(); // ensuite ca depend si le service est local ou distant // local = local://fqn // sinon, c'est distant if ("local".equalsIgnoreCase(protocole)) { String fqClassImpl = host; log.debug("Trying to load local service : " + fqClassImpl); // instanciation dynamique try { Class resultClass = (Class) Class .forName(fqClassImpl); serviceimpl = resultClass.newInstance(); serviceimpl.init(defaultServiceContext .beginTransaction()); // mise en cache // sauf dans le cas ou il y a un "#new" a la fin de // l'uri if (!"new".equalsIgnoreCase(fragment)) { mapServiceCache.put(serviceclazz, serviceimpl); } } catch (ClassNotFoundException eee) { throw new TopiaException("Can't find service class " + fqClassImpl); } catch (InstantiationException eee) { throw new TopiaException( "Can't instanciate service class " + fqClassImpl); } catch (IllegalAccessException eee) { throw new TopiaException("Can't access service class " + fqClassImpl); } } // prefix non local => proxy else { log.debug("Trying to get remote service : " + serviceUrl); TopiaProxy tProxy = getProxyForURI(uriService); if (tProxy == null) { log.debug("Unsupported protocole : " + protocole); } else { tProxy.setURI(uriService); tProxy.setClass(serviceclazz); // le proxy tProxy definit suivant le protocole // gere maintenant tous les appels sur l'interface // demandee (serviceclazz) serviceimpl = (E) Proxy.newProxyInstance(serviceclazz .getClassLoader(), new Class[] { serviceclazz }, tProxy); // mise en cache mapServiceCache.put(serviceclazz, serviceimpl); } } } catch (URISyntaxException e) { if(log.isWarnEnabled()) { log.warn("URI for service '" + serviceclazz.getCanonicalName() + "' is invalid !", e); } } } return serviceimpl; } /** * Retourne l'implementation d'un TopiaProxy en fonction du protocole de * l'URI * * @param uriService * @return l'implementation ou null si le protocol n'est pas géré */ protected static TopiaProxy getProxyForURI(URI uriService) { // result TopiaProxy tProxy = null; if ("rmi".equalsIgnoreCase(uriService.getScheme())) { tProxy = new RMIProxy(); } else if ("xml-rpc".equalsIgnoreCase(uriService.getScheme())) { tProxy = new XMLRPCProxy(); } else if ("soap".equalsIgnoreCase(uriService.getScheme())) { tProxy = new SOAPProxy(); } return tProxy; } /** * Ajoute un service fournit par ToPIA. * * @param interfaze * l'interface du service * @param clazz * la classe qui permet de creer des instances de * l'implementation du service * @param protocoles * les protocoles de diffusion du service * * @see TopiaApplicationService */ public static void addService( Class interfaze, Class clazz, Protocol... protocoles) { log.debug("Adding service for '" + interfaze + "' in protocoles : " + Arrays.toString(protocoles)); for (Protocol protocole : protocoles) { mainDispatcher.addServiceClass(interfaze, clazz, protocole); } } /** * Ajoute un service fournit par ToPIA. * * Celle-ci renvoie toujours la meme instance du service. * * @param * un type qui etend TopiaApplicationService * @param interfaze * l'interface du service * @param instance * l'instance de l'implementation du service * @param protocoles * les protocoles de diffusion du service * * @see TopiaApplicationService */ public static void addService( Class interfaze, E instance, Protocol... protocoles) { log.debug("Adding service for '" + interfaze + "'(unique instance) in protocoles : " + Arrays.toString(protocoles)); for (Protocol protocole : protocoles) { mainDispatcher.addServiceInstance(interfaze, instance, protocole); } } }