/*
* Claudia Project
* http://claudia.morfeo-project.org
*
* (C) Copyright 2010 Telefonica Investigacion y Desarrollo
* S.A.Unipersonal (Telefonica I+D)
*
* See CREDITS file for info about members and contributors.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the Affero GNU General Public License (AGPL) 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 Public License for more details.
*
* You should have received a copy of the Affero GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* If you want to use this software an plan to distribute a
* proprietary application in any way, and you are not licensing and
* distributing your source code under AGPL, you probably need to
* purchase a commercial license of the product. Please contact
* claudia-support@lists.morfeo-project.org for more information.
*/
package com.telefonica.claudia.smi.deployment;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueBrowser;
import javax.jms.Session;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.spi.InitialContextFactory;
import org.apache.log4j.Logger;
import com.telefonica.claudia.slm.eventsBus.events.Event;
import com.telefonica.claudia.slm.eventsBus.events.SMIChannelEvent;
import com.telefonica.claudia.slm.eventsBus.events.Event.EventType;
import com.telefonica.claudia.slm.eventsBus.events.SMIChannelEvent.SMIAction;
import com.telefonica.claudia.smi.Main;
import com.telefonica.claudia.smi.URICreation;
import com.telefonica.claudia.smi.task.Task;
import com.telefonica.claudia.smi.task.TaskManager;
public class SMDeploymentDriver implements DeploymentDriver {
private static Logger log = Logger.getLogger("com.telefonica.claudia.smi.SMPlugin");
private static final int EVENT_BUS_TIMEOUT=15*60*1000;
private Queue smiChannelRequest = null;
private Queue smiChannelReply = null;
private MessageProducer smiChannelProducer = null;
private Session session = null;
Context initialContext = null;
private Connection connection = null;
private static final String DEFAULT_CONN_FACTORY_NAME = "ConnectionFactory";
private String connFactoryName = null;
private static final String JNDI_SERVER_PROVIDER_URL = "java.naming.provider.url";
private static final String JNDI_NAMING_FACTORY = "java.naming.factory.initial";
private String serverProviderUrl = null;
private String namingFactory = null;
public class UndeployServiceTask extends Task {
String fqn;
public UndeployServiceTask(String fqn) {
super();
this.fqn = fqn;
}
@Override
public void execute() {
status = TaskStatus.QUEUED;
// Send the undeploy message.
try {
undeploy(fqn);
status = TaskStatus.SUCCESS;
} catch (JMSException e) {
log.error("Error connecting with the SLM. Task could not be completed: " + e.getMessage());
status = TaskStatus.ERROR;
} catch (IOException e) {
log.error("Unknown IO Error. Task could not be completed: " + e.getMessage());
status = TaskStatus.ERROR;
}
this.endTime = System.currentTimeMillis();
}
/**
* Undeploy the selected service.
*
* @param receives
* A String representation of the service's FQN
*/
public void undeploy(String serviceFQNRep) throws JMSException, IOException {
SMIChannelEvent smi = new SMIChannelEvent(0, 0, SMIAction.UNDEPLOY);
try {
smi.put(SMIChannelEvent.FQN_ID, serviceFQNRep);
smiChannelProducer.send(session.createObjectMessage(smi));
} catch (JMSException e) {
log.error("SMPlugin: Communicatin error accessing the Service Manager. Service was not deployed",e);
}
// Wait until the Service is deployed.
MessageConsumer messageConsumer = session.createConsumer(smiChannelReply, "service = '" + serviceFQNRep + "'");
ObjectMessage m = (ObjectMessage) messageConsumer.receive(EVENT_BUS_TIMEOUT);
if (m==null) {
log.error("Timeout waiting for a server response. Try later.");
throw new IOException("Timeout waiting for a server response. Try later.");
}
messageConsumer.close();
log.info("SMPlugin: Undeployment of service launched");
return;
}
}
public class DeployServiceTask extends Task {
String fqnCustomer;
String serviceName;
String ovf;
public DeployServiceTask(String fqn, String serviceName, String ovf) {
super();
this.fqnCustomer= fqn;
this.serviceName= serviceName;
this.ovf= ovf;
}
@Override
public void execute() {
status = TaskStatus.RUNNING;
try {
if (deploy())
status = TaskStatus.SUCCESS;
else
status = TaskStatus.ERROR;
this.endTime = System.currentTimeMillis();
} catch (JMSException e) {
status = TaskStatus.ERROR;
error = new TaskError();
error.message = "JMS exception connecting with the SLM: " + e.getMessage();
} catch (IOException e) {
status = TaskStatus.ERROR;
error = new TaskError();
error.message = "Unknown IO Error connecting with the SLM: " + e.getMessage();
}
}
/**
* Deploys a service application for the customer passed as a parameter.
*
* @param domR
* String with a XML representation of the service in OVF format.
*
* @param customerName
* Receives a String representation of the service's name
*
* @return String
* Service name assigned by the LCC (reservoir's FQN)
*
* @throws IOException
* If the XML representation of the service is not well formed.
*
* @throws JMSException
* If its not possible to connect to the event bus.
*/
public boolean deploy() throws JMSException, IOException {
log.info("Sending deploying message for service ["+serviceName+"] of user [" + fqnCustomer +"]");
SMIChannelEvent smi = new SMIChannelEvent(System.currentTimeMillis(), 0, SMIAction.DEPLOY);
smi.put(SMIChannelEvent.OVF_DOCUMENT, ovf);
smi.put(SMIChannelEvent.CUSTOMER_NAME, fqnCustomer);
smi.put(SMIChannelEvent.SERVICE_NAME, serviceName);
smiChannelProducer.send(session.createObjectMessage(smi));
// Wait until the Service is deployed.
log.info("Waiting for the answer of the SLM.");
MessageConsumer messageConsumer = session.createConsumer(smiChannelReply, "customer = '" + fqnCustomer + "'");
ObjectMessage m = (ObjectMessage) messageConsumer.receive(EVENT_BUS_TIMEOUT);
if (m==null) {
log.error("Timeout waiting for a server response. Try later.");
error = new TaskError();
error.message = "Timeout waiting for a server response. The service may not have been deployed.";
return false;
}
smi = (SMIChannelEvent) m.getObject();
String serviceFQN= smi.get(SMIChannelEvent.FQN_ID);
log.info("FQN name for the service received: " + serviceFQN);
messageConsumer.close();
this.returnMsg = serviceFQN;
log.info("SMPlugin: Deployment of service " + serviceFQN + " launched");
return true;
}
}
public SMDeploymentDriver(Properties prop) throws NamingException, JMSException, ClassNotFoundException {
// Creates the bus manager and attach it to the context as an attribte.
try {
this.connFactoryName = DEFAULT_CONN_FACTORY_NAME;
namingFactory = prop.getProperty(JNDI_NAMING_FACTORY);
serverProviderUrl = prop.getProperty(JNDI_SERVER_PROVIDER_URL);
// Open the JMS Session to create the queue conections
openJMSSession();
cleanQueues();
smiChannelProducer = session.createProducer(smiChannelRequest);
} catch (JMSException e) {
log.error("The connection to the bus could not be created. " + e.getMessage());
throw e;
} catch (ClassNotFoundException e) {
log.error("The Factory class could not be found");
throw e;
}
}
@SuppressWarnings("unchecked")
private void cleanQueues() {
log.error("Clean the queues from lost replys. ");
if (session== null) return;
try {
QueueBrowser qb = session.createBrowser(smiChannelRequest);
Enumeration e = qb.getEnumeration();
MessageConsumer messageConsumer = session.createConsumer(smiChannelRequest);
int n=0;
while (e.hasMoreElements()) {
e.nextElement();
n++;
}
for (int i =0; i < n; i++) {
log.info("Deleting pending messages...");
messageConsumer.receive(EVENT_BUS_TIMEOUT);
}
messageConsumer.close();
try { Thread.sleep(5000); } catch (InterruptedException ex) { }
} catch (JMSException e) {
log.warn("Exception cleaning the queue. Execution might continue without errors: " + e.getMessage());
}
}
private void openJMSSession() throws NamingException, JMSException, ClassNotFoundException {
log.info("Getting initial JNDI context");
Hashtable<String, String> jndiContext = getJNDIEnv();
SMDeploymentDriver.class.getClassLoader().loadClass(namingFactory);
Class classFactory = Class.forName(namingFactory, true, SMDeploymentDriver.class.getClassLoader());
try {
InitialContextFactory icFactory = (InitialContextFactory) classFactory.getConstructor().newInstance();
initialContext = icFactory.getInitialContext(jndiContext);
} catch (Exception e) {
log.error("It wasn't possible to create the initialContext: " + e.getMessage());
throw new NamingException("It wasn't possible to create the initialContext: " + e.getMessage());
}
log.info("Looking up for JMS connection factory " + connFactoryName);
ConnectionFactory connectionFactory = (ConnectionFactory) initialContext.lookup(connFactoryName);
log.info("Creating connection to bus");
connection = connectionFactory.createConnection();
connection.start();
log.info("Creating session");
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
log.info("Getting queue for event type " + EventType.SMI_CHANNEL_EVENT);
smiChannelRequest = (Queue)initialContext.lookup(Event.busQueueForEventType(EventType.SMI_CHANNEL_EVENT, false));
smiChannelReply = (Queue)initialContext.lookup(Event.busQueueForEventType(EventType.SMI_CHANNEL_EVENT, true));
}
@SuppressWarnings("unchecked")
public Hashtable<String, String> getJNDIEnv() {
Hashtable env = new Hashtable();
//env.put(Context.INITIAL_CONTEXT_FACTORY, namingFactory);
env.put(Context.PROVIDER_URL, serverProviderUrl);
env.put("queue.SMI_CHANNEL_EVENT_REQUEST", "SMI_CHANNEL_REQUEST");
env.put("queue.SMI_CHANNEL_EVENT_REPLY", "SMI_CHANNEL_REPLY");
return env;
}
public long deploy(String fqnCustomer, String serviceName, String ovf)
throws IOException {
Task deployTask = new DeployServiceTask(fqnCustomer, serviceName, ovf);
deployTask.setResource("http://" + Main.serverHost + ":" + Main.serverPort + URICreation.getURIVDC(fqnCustomer) + "/vapp/" + serviceName, URICreation.VDC_MIME_TYPE);
return TaskManager.getInstance().addTask(deployTask, fqnCustomer).getTaskId();
}
// public long createVdc(String fqnCustomer, String vdc) throws IOException {
// //TODO: Must be implemented when clotho supports VDC creation
// return -1;
// }
//public long createVdc(String fqnCustomer, String vdc) throws IOException
//{
//TODO: Must be implemented when clotho supports VDC creation
// return -1;
// }
public long createVdc(String orgname, String vdc) throws IOException
{
log.info("Sending deploying VDC message for customer ["+orgname+"] of user [" + vdc +"]");
SMIChannelEvent smi = new SMIChannelEvent(System.currentTimeMillis(), 0, SMIAction.DEPLOY_VDC);
String fqn= "Dddd";
//smi.put(SMIChannelEvent.OVF_DOCUMENT, ovf);
//smi.put(SMIChannelEvent.ORG_DESCRIPTION, orgname);
//smi.put(SMIChannelEvent.CUSTOMER_NAME, vdc);
smi.put(SMIChannelEvent.FQN_ID, fqn);
//smi.put(SMIChannelEvent.SERVICE_NAME, serviceName);
try {
smiChannelProducer.send(session.createObjectMessage(smi));
// Wait until the Service is deployed.
System.out.println ("event received");
MessageConsumer messageConsumer = session.createConsumer(smiChannelReply, "org = '" + fqn + "'");
System.out.println (messageConsumer);
ObjectMessage m = (ObjectMessage) messageConsumer.receive(EVENT_BUS_TIMEOUT);
if (m==null) {
log.error("Timeout waiting for a server response. Try later.");
throw new IOException("Timeout waiting for a server response. Try later.");
}
System.out.println (m);
smi = (SMIChannelEvent) m.getObject();
System.out.println (smi);
if (smi.isSuccess()){
String serviceDescription= smi.get(SMIChannelEvent.ORG_DESCRIPTION);
log.info("SMPlugin: Customer data retrieved");
messageConsumer.close();
return 2;
}
String serviceFQN = "0";
log.info("SMPlugin: Deployment of service " + serviceFQN + " launched");
return new Long(serviceFQN).longValue();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return -1;
}
public String getOrg(String fqn) throws IOException {
System.out.println ("Get Org " + fqn);
String serviceDescription = null;
SMIChannelEvent smi = new SMIChannelEvent(0, 0, SMIAction.GET_ORG);
try {
smi.put(SMIChannelEvent.FQN_ID, fqn);
smiChannelProducer.send(session.createObjectMessage(smi));
// Wait until the Service is deployed.
System.out.println ("event received");
MessageConsumer messageConsumer = session.createConsumer(smiChannelReply, "org = '" + fqn + "'");
System.out.println (messageConsumer);
ObjectMessage m = (ObjectMessage) messageConsumer.receive(EVENT_BUS_TIMEOUT);
if (m==null) {
log.error("Timeout waiting for a server response. Try later.");
throw new IOException("Timeout waiting for a server response. Try later.");
}
System.out.println (m);
smi = (SMIChannelEvent) m.getObject();
System.out.println (smi);
if (smi.isSuccess()){
serviceDescription= smi.get(SMIChannelEvent.ORG_DESCRIPTION);
log.info("SMPlugin: Organization data retrieved");
messageConsumer.close();
return serviceDescription;
}
else{
System.out.println ("No object received correctly ");
messageConsumer.close();
return null;
}
// smi = (SMIChannelEvent) m.getObject();
// String serviceDescription= smi.get(SMIChannelEvent.ORG_DESCRIPTION);
} catch (JMSException e) {
log.error("SMDeploymentDriver: Communication error accessing the SLM. Impossible to retrieve customer data.",e);
throw new IOException("SMDeploymentDriver: Communication error accessing the SLM. Impossible to retrieve customer data." + e.getMessage());
}
}
public String getVdc(String fqn) throws IOException {
SMIChannelEvent smi = new SMIChannelEvent(0, 0, SMIAction.GET_VDC);
try {
smi.put(SMIChannelEvent.FQN_ID, fqn);
smiChannelProducer.send(session.createObjectMessage(smi));
// Wait until the Service is deployed.
MessageConsumer messageConsumer = session.createConsumer(smiChannelReply, "customer = '" + fqn + "'");
ObjectMessage m = (ObjectMessage) messageConsumer.receive(EVENT_BUS_TIMEOUT);
if (m==null) {
log.error("Timeout waiting for a server response. Try later.");
throw new IOException("Timeout waiting for a server response. Try later.");
}
smi = (SMIChannelEvent) m.getObject();
String serviceDescription= smi.get(SMIChannelEvent.CUSTOMER_DESCRIPTION);
messageConsumer.close();
log.info("SMPlugin: Customer data retrieved");
return serviceDescription;
} catch (JMSException e) {
log.error("SMDeploymentDriver: Communication error accessing the SLM. Impossible to retrieve customer data.",e);
throw new IOException("SMDeploymentDriver: Communication error accessing the SLM. Impossible to retrieve customer data." + e.getMessage());
}
}
public String getService(String fqn) throws IOException {
SMIChannelEvent smi = new SMIChannelEvent(0, 0, SMIAction.GET_VAPP);
try {
smi.put(SMIChannelEvent.FQN_ID, fqn);
smiChannelProducer.send(session.createObjectMessage(smi));
// Wait until the Service is deployed.
MessageConsumer messageConsumer = session.createConsumer(smiChannelReply, "service = '" + fqn + "'");
ObjectMessage m = (ObjectMessage) messageConsumer.receive(EVENT_BUS_TIMEOUT);
if (m==null) {
log.error("Timeout waiting for a server response. Try later.");
throw new IOException("Timeout waiting for a server response. Try later.");
}
smi = (SMIChannelEvent) m.getObject();
String serviceDescription= smi.get(SMIChannelEvent.SERVICE_DESCRIPTION);
messageConsumer.close();
log.info("SMPlugin: Service data retrieved");
return serviceDescription;
} catch (JMSException e) {
log.error("SMDeploymentDriver: Communication error accessing the SLM. Impossible to retrieve service data.",e);
throw new IOException("SMDeploymentDriver: Communication error accessing the SLM. Impossible to retrieve service data." + e.getMessage());
}
}
public String getVee(String fqn) throws IOException {
SMIChannelEvent smi = new SMIChannelEvent(0, 0, SMIAction.GET_VEE);
try {
smi.put(SMIChannelEvent.FQN_ID, fqn);
smiChannelProducer.send(session.createObjectMessage(smi));
// Wait until the Service is deployed.
MessageConsumer messageConsumer = session.createConsumer(smiChannelReply, "vee = '" + fqn + "'");
ObjectMessage m = (ObjectMessage) messageConsumer.receive(EVENT_BUS_TIMEOUT);
if (m==null) {
log.error("Timeout waiting for a server response. Try later.");
throw new IOException("Timeout waiting for a server response. Try later.");
}
smi = (SMIChannelEvent) m.getObject();
String serviceDescription= smi.get(SMIChannelEvent.VEE_DESCRIPTION);
messageConsumer.close();
log.info("SMPlugin: VEE data retrieved");
return serviceDescription;
} catch (JMSException e) {
log.error("SMDeploymentDriver: Communication error accessing the SLM. Impossible to retrieve VEE data.",e);
throw new IOException("SMDeploymentDriver: Communication error accessing the SLM. Impossible to retrieve VEE data." + e.getMessage());
}
}
public void undeploy(String fqn) throws IOException {
TaskManager.getInstance().addTask(new UndeployServiceTask(fqn), URICreation.getVDC(fqn)).getTaskId();
}
/**
* Retrieves information on the selected org.
*
* @param fqn
* FQN of the service to retrieve.
*
* @return
* XML Representation of the org
*
* @throws IOException
*/
}