/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This 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 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.profileservice.management.templates;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElements;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlValue;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.jboss.deployers.spi.management.DeploymentTemplate;
import org.jboss.deployers.vfs.spi.client.VFSDeployment;
import org.jboss.managed.api.DeploymentTemplateInfo;
import org.jboss.managed.api.ManagedProperty;
import org.jboss.managed.api.annotation.ViewUse;
import org.jboss.metatype.api.types.CompositeMetaType;
import org.jboss.metatype.api.values.CompositeValue;
import org.jboss.metatype.api.values.MapCompositeValueSupport;
import org.jboss.metatype.api.values.MetaValue;
import org.jboss.metatype.api.values.MetaValueFactory;
import org.jboss.metatype.api.values.SimpleValue;
import org.jboss.metatype.plugins.values.MetaValueFactoryBuilder;
import org.jboss.virtual.VFS;
import org.jboss.virtual.VirtualFile;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* A template for creating jms destinations
*
* @author <a href="mailto:alex@jboss.org">Alexey Loubyansky</a>
* @author <a href="mailto:emuckenh@redhat.com">Emanuel Muckenhuber</a>
* @version <tt>$Revision: 87482 $</tt>
*/
public class JmsDestinationTemplate
implements DeploymentTemplate
{
/** The file suffix. */
private static final String FILE_SUFFIX = "-service.xml";
/** The role attributes. */
protected static final String[] attributes = new String[] { "read", "write", "create"};
private static final MetaValueFactory mvf = MetaValueFactoryBuilder.create();
private DeploymentTemplateInfo info;
public String getDeploymentName(String deploymentBaseName)
{
if(deploymentBaseName == null)
throw new IllegalArgumentException("Null base name.");
if(deploymentBaseName.endsWith(FILE_SUFFIX) == false)
deploymentBaseName = deploymentBaseName + FILE_SUFFIX;
return deploymentBaseName;
}
public DeploymentTemplateInfo getInfo()
{
return info;
}
public void setInfo(DeploymentTemplateInfo info)
{
this.info = info;
}
public VirtualFile applyTemplate(VirtualFile root, String deploymentBaseName,
DeploymentTemplateInfo values)
throws Exception
{
return applyTemplate(values);
}
public VirtualFile applyTemplate(DeploymentTemplateInfo values) throws Exception
{
// Create a temp file
File dsXml = File.createTempFile(getClass().getSimpleName(), FILE_SUFFIX);
// Write template
writeTemplate(dsXml, values);
// Return virtual file
return VFS.getRoot(dsXml.toURI());
}
public void updateTemplateDeployment(VFSDeployment ctx, DeploymentTemplateInfo values) throws Exception
{
}
private void writeTemplate(File dsXml, DeploymentTemplateInfo info)
throws Exception
{
if(info == null)
throw new IllegalArgumentException("Null template info.");
if(info.getProperties() == null)
throw new IllegalArgumentException("Null template info.");
// Look for the destination type using the destinationType ManagedProperty
ManagedProperty destTypeMP = info.getProperties().get("destinationType");
String destinationType = null;
if(destTypeMP == null)
{
// Try casting this to a DsDataSourceTemplateInfo
destinationType = ((JmsDestinationTemplateInfo)info).getDestinationType();
}
else
{
SimpleValue dsTypeSV = (SimpleValue) destTypeMP.getValue();
destinationType = dsTypeSV.getValue().toString();
}
JmsDestinationMetaData destination = new JmsDestinationMetaData();
String destinationName = (String) getProperty(info, "name");
String jndiName = (String) getProperty(info, "JNDIName");
if(jndiName == null)
throw new IllegalStateException("Null jndi name.");
if(destinationName == null)
destinationName = jndiName;
if("QueueTemplate".equals(destinationType))
{
destination.className = "org.jboss.jms.server.destination.QueueService";
// destination.annotation =
// "@org.jboss.system.deployers.managed.ManagementObjectClass(code=org.jboss.jms.server.destination.QueueServiceMO)";
destination.xmbeanDd = "xmdesc/Queue-xmbean.xml";
destination.jmxName = "jboss.messaging.destination:service=Queue,name=" + destinationName;
}
else if("TopicTemplate".equals(destinationType))
{
destination.className = "org.jboss.jms.server.destination.TopicService";
// destination.annotation =
// "@org.jboss.system.deployers.managed.ManagementObjectClass(code=org.jboss.jms.server.destination.TopicServiceMO)";
destination.xmbeanDd = "xmdesc/Topic-xmbean.xml";
destination.jmxName = "jboss.messaging.destination:service=Topic,name=" + destinationName;
}
else
{
throw new IllegalStateException("Unsupported destination type: " + destinationType);
}
List<JmsAttribute> attributes = new ArrayList<JmsAttribute>();
destination.attribute = attributes;
Map<String, ManagedProperty> properties = info.getProperties();
for(ManagedProperty p : properties.values())
{
// Get the value
MetaValue v = p.getValue();
String name = p.getName();
// Check if we need to skip a property
boolean skip = p.hasViewUse(ViewUse.CONFIGURATION) == false
|| p.isReadOnly()
|| p.isRemoved();
// Don't skip clustered, which is a read
if(skip)
{
if(name.equals("clustered"))
skip = false;
}
if(skip)
continue;
// Skip null values
if(v == null)
continue;
// Skip the destinationType
if(p == destTypeMP)
continue;
char c = name.charAt(0);
if(Character.isLowerCase(c))
name = Character.toUpperCase(c) + name.substring(1);
JmsAttribute attribute = null;
if(v.getMetaType().isSimple())
{
attribute = new JmsAttributeMetaData(name, "" + ((SimpleValue)v).getValue());
}
else
{
if(name.equals("DLQ"))
{
String n = (String) mvf.unwrap(v);
attribute = new JmsAttributeMetaData("DLQ", n);
}
else if(name.equals("ExpiryQueue"))
{
String n = (String) mvf.unwrap(v);
attribute = new JmsAttributeMetaData("ExpiryQueue", n);
}
else if(name.equals("SecurityConfig"))
{
Element e = unwrapMetaValue((MapCompositeValueSupport) v);
if(e != null)
attribute = new JmsElementMetaData("SecurityConfig", e);
}
}
if(attribute != null)
attributes.add(attribute);
}
// Add dependencies
List<JmsDependencyMetaData> depends = new ArrayList<JmsDependencyMetaData>();
destination.depends = depends;
// Set server peer
String serverPeer = (String) getProperty(info, "serverPeer");
if(serverPeer != null)
{
depends.add(new JmsDependencyMetaData("ServerPeer", serverPeer));
}
else
{
depends.add(new JmsDependencyMetaData("ServerPeer", "jboss.messaging:service=ServerPeer"));
}
// <depends>
depends.add(new JmsDependencyMetaData("jboss.messaging:service=PostOffice"));
JmsDestinationDeployment deployment = new JmsDestinationDeployment();
deployment.destination = destination;
Class<?>[] classes = {JmsDestinationDeployment.class};
JAXBContext context = JAXBContext.newInstance(classes);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty("jaxb.formatted.output", Boolean.TRUE);
JAXBElement<JmsDestinationDeployment> root =
new JAXBElement<JmsDestinationDeployment>(
new javax.xml.namespace.QName("server"),
JmsDestinationDeployment.class,
null, deployment
);
FileWriter fw = null;
try
{
fw = new FileWriter(dsXml);
marshaller.marshal(root, fw);
}
finally
{
if(fw != null)
{
fw.close();
}
}
}
/**
* Extract the value from the property MetaValue
* @param info - template info
* @param propName - the name of the property to return a value for
* @return the unwrapped property value
*/
private Object getProperty(DeploymentTemplateInfo info, String propName)
{
Map<String, ManagedProperty> propsInfo = info.getProperties();
ManagedProperty prop = propsInfo.get(propName);
if(prop == null)
{
return null;
}
Object value = prop.getValue();
if(value instanceof MetaValue)
{
return mvf.unwrap((MetaValue) value);
}
return value;
}
/**
* Unwrap the value.
* TODO This should actually be done by the SecurityConfigMapper and
* the metaValueFacotyr
*
* @param metaValue the meta value
* @return the element
*/
protected Element unwrapMetaValue(MapCompositeValueSupport metaValue)
{
if(metaValue == null)
return null;
MapCompositeValueSupport value = (MapCompositeValueSupport) metaValue;
CompositeMetaType metaType = value.getMetaType();
// Don't create a empty set
if(metaType.itemSet().isEmpty())
return null;
// Create the dom document
Document d = createDocument();
// Security
Element security = d.createElement("security");
// Get the roles
for(String name : metaType.itemSet())
{
// Role
CompositeValue row = (CompositeValue) value.get(name);
if(row == null)
continue;
Element role = d.createElement("role");
role.setAttribute("name", name);
// For each attribute: read, write, create
for(String attribute : attributes)
{
SimpleValue v = (SimpleValue) row.get(attribute);
if(v != null && v.getValue() != null)
{
role.setAttribute(attribute, ((Boolean)v.getValue()).toString());
}
}
security.appendChild(role);
}
return security;
}
protected static Document createDocument()
{
try
{
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
return db.newDocument();
}
catch(Exception e)
{
throw new RuntimeException(e);
}
}
// the classes below should go away and ServiceDeployment and MetaData
// API should be used instead once their bound with JAXB
@XmlRootElement(name = "server")
public static class JmsDestinationDeployment
{
@XmlElement(name = "mbean")
public JmsDestinationMetaData destination;
}
public static class JmsDestinationMetaData
{
@XmlAttribute(name = "code")
String className;
@XmlAttribute(name = "name")
String jmxName;
@XmlAttribute(name = "xmbean-dd")
String xmbeanDd;
@XmlElement
String annotation;
@XmlElements(value = {
@XmlElement(type = JmsAttributeMetaData.class),
@XmlElement(type = JmsElementMetaData.class) })
public List<JmsAttribute> attribute;
public List<JmsDependencyMetaData> depends;
}
public static class JmsAttributeMetaData implements JmsAttribute
{
@XmlAttribute
String name;
@XmlValue
String value;
public JmsAttributeMetaData()
{
}
public JmsAttributeMetaData(String name, String value)
{
this.name = name;
this.value = value;
}
}
public static class JmsElementMetaData implements JmsAttribute
{
@XmlAttribute
String name;
@XmlAnyElement
Element value;
public JmsElementMetaData()
{
}
public JmsElementMetaData(String name, Element value)
{
this.name = name;
this.value = value;
}
}
public static class JmsDependencyMetaData
{
@XmlAttribute(name = "optional-attribute-name")
String attribute;
@XmlValue
String value;
public JmsDependencyMetaData()
{
}
public JmsDependencyMetaData(String value)
{
this.value = value;
}
public JmsDependencyMetaData(String attribute, String value)
{
this.attribute = attribute;
this.value = value;
}
}
public static interface JmsAttribute
{
// workaround jaxb
}
}