001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.services.binding;
023:
024: import java.util.HashMap;
025: import java.beans.PropertyEditorManager;
026: import java.beans.PropertyEditor;
027: import javax.management.Attribute;
028: import javax.management.MBeanServer;
029: import javax.management.ObjectName;
030: import javax.management.MBeanInfo;
031: import javax.management.MBeanAttributeInfo;
032:
033: import org.w3c.dom.Element;
034: import org.w3c.dom.NodeList;
035:
036: import org.jboss.logging.Logger;
037: import org.jboss.metadata.MetaData;
038: import org.jboss.util.StringPropertyReplacer;
039: import org.jboss.util.Classes;
040: import org.jboss.deployment.DeploymentException;
041:
042: /** An implementation of the ServicesConfigDelegate that expects a delegate-config
043: element of the form:
044: <delegate-config portName="portAttrName" hostName="hostAttrName">
045: <attribute name="mbeanAttrName">host-port-expr</attribute>
046: ...
047: </delegate-config>
048: where the portAttrName is the attribute name of the mbean service
049: to which the (int port) value should be applied and the hostAttrName
050: is the attribute name of the mbean service to which the (String virtualHost)
051: value should be applied.
052:
053: Any mbeanAttrName attribute reference has the corresponding value replaced
054: with any ${host} and ${port} references with the associated host and port
055: bindings.
056:
057: @author Scott.Stark@jboss.org
058: @version $Revision: 57210 $
059: */
060: public class AttributeMappingDelegate implements ServicesConfigDelegate {
061: private static Logger log = Logger
062: .getLogger(AttributeMappingDelegate.class);
063:
064: /** Take the given config and map it onto the service specified in the
065: config using JMX via the given server.
066: @param config, the service name and its config bindings
067: @param server, the JMX server to use to apply the config
068: */
069: public void applyConfig(ServiceConfig config, MBeanServer server)
070: throws Exception {
071: Element delegateConfig = (Element) config
072: .getServiceConfigDelegateConfig();
073: if (delegateConfig == null)
074: throw new IllegalArgumentException(
075: "ServiceConfig.ServiceConfigDelegateConfig is null");
076: // Check for a port and host name
077: String portAttrName = delegateConfig.getAttribute("portName");
078: if (portAttrName.length() == 0)
079: portAttrName = null;
080: String hostAttrName = delegateConfig.getAttribute("hostName");
081: if (hostAttrName.length() == 0)
082: hostAttrName = null;
083:
084: // Check for any arbitrary attributes
085: NodeList attributes = delegateConfig
086: .getElementsByTagName("attribute");
087:
088: // Only the first binding is used as only one (host,port) pair is mapped
089: ServiceBinding[] bindings = config.getBindings();
090: if (bindings != null && bindings.length > 0) {
091: // Build a mapping of the attribute names to their type name
092: ObjectName serviceName = new ObjectName(config
093: .getServiceName());
094: MBeanInfo info = server.getMBeanInfo(serviceName);
095: MBeanAttributeInfo[] attrInfo = info.getAttributes();
096: HashMap attrTypeMap = new HashMap();
097: for (int a = 0; a < attrInfo.length; a++) {
098: MBeanAttributeInfo attr = attrInfo[a];
099: attrTypeMap.put(attr.getName(), attr.getType());
100: }
101:
102: int port = bindings[0].getPort();
103: String host = bindings[0].getHostName();
104: // Apply the port setting override if the port name was given
105: if (portAttrName != null) {
106: Attribute portAttr = new Attribute(portAttrName,
107: new Integer(port));
108: log.debug("setPort, name='" + portAttrName + "' value="
109: + port);
110: server.setAttribute(serviceName, portAttr);
111: }
112: // Apply the host setting override if the port name was given
113: if (hostAttrName != null) {
114: Attribute hostAttr = createAtribute(port, host,
115: attrTypeMap, hostAttrName, host);
116: log.debug("setHost, name='" + hostAttrName + "' value="
117: + host);
118: server.setAttribute(serviceName, hostAttr);
119: }
120:
121: /* Apply any other host/port based attributes with replacement of
122: the ${host} and ${port} strings.
123: */
124: for (int a = 0; a < attributes.getLength(); a++) {
125: Element attr = (Element) attributes.item(a);
126: String name = attr.getAttribute("name");
127: if (name.length() == 0)
128: throw new IllegalArgumentException(
129: "attribute element #" + a
130: + " has no name attribute");
131: String attrExp = MetaData.getElementContent(attr);
132: Attribute theAttr = createAtribute(port, host,
133: attrTypeMap, name, attrExp);
134: server.setAttribute(serviceName, theAttr);
135: }
136: }
137: }
138:
139: /** Create a JMX Attribute with the correct type value object. This
140: * converts the given attrExp into an Attribute for attrName with
141: * replacement of any ${host} ${port} references in the attrExp
142: * replaced with the given port/host values.
143: * @param port The binding port value
144: * @param host The binding host value
145: * @param attrTypeMap the name to type map for the service attributes
146: * @param attrName the name of the attribute to create
147: * @param attrExp the string exp for the attribute value
148: * @return the JMX attribute instance
149: * @throws Exception thrown on an invalid attribute name or inability
150: * to find a valid property editor
151: */
152: private Attribute createAtribute(int port, String host,
153: HashMap attrTypeMap, String attrName, String attrExp)
154: throws Exception {
155: String attrText = replaceHostAndPort(attrExp, host, "" + port);
156: String typeName = (String) attrTypeMap.get(attrName);
157: if (typeName == null) {
158: throw new DeploymentException("No such attribute: "
159: + attrName);
160: }
161: // Convert the type
162: Class attrType = Classes.loadClass(typeName);
163: PropertyEditor editor = PropertyEditorManager
164: .findEditor(attrType);
165: if (editor == null) {
166: String msg = "No property editor for attribute: "
167: + attrName + "; type=" + typeName;
168: throw new DeploymentException(msg);
169: }
170: editor.setAsText(attrText);
171: Object attrValue = editor.getValue();
172: log.debug("setAttribute, name='" + attrName + "', text="
173: + attrText + ", value=" + attrValue);
174: Attribute theAttr = new Attribute(attrName, attrValue);
175: return theAttr;
176: }
177:
178: /** Loop over text and replace any ${host} and ${port} strings. If there are
179: * any ${x} system property references in the resulting replacement string
180: * these will be replaced with the corresponding System.getProperty("x")
181: * value if one exists.
182: * @param text the text exp with optional ${host} ${port} references
183: * @param host the binding host value
184: * @param port the binding port value
185: */
186: private String replaceHostAndPort(String text, String host,
187: String port) {
188: if (text == null)
189: return null;
190:
191: StringBuffer replacement = new StringBuffer(text);
192: if (host == null)
193: host = "localhost";
194: // Simple looping should be replaced with regex package
195: String test = replacement.toString();
196: int index;
197: while ((index = test.indexOf("${host}")) >= 0) {
198: replacement.replace(index, index + 7, host);
199: test = replacement.toString();
200: }
201: while ((index = test.indexOf("${port}")) >= 0) {
202: replacement.replace(index, index + 7, port);
203: test = replacement.toString();
204: }
205: return StringPropertyReplacer.replaceProperties(replacement
206: .toString());
207: }
208: }
|