001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.catalina.ant.jmx;
019:
020: import java.io.IOException;
021: import java.net.MalformedURLException;
022:
023: import javax.management.MBeanServerConnection;
024: import javax.management.ObjectName;
025:
026: import org.apache.tools.ant.BuildException;
027: import org.apache.tools.ant.ProjectComponent;
028: import org.apache.tools.ant.taskdefs.condition.Condition;
029:
030: /**
031: *
032: * <b>Definition</b>:
033: * <pre>
034: * <path id="catalina_ant">
035: * <fileset dir="${catalina.home}/server/lib">
036: * <include name="catalina-ant.jar"/>
037: * <include name="catalina-ant-jmx.jar"/>
038: * </fileset>
039: * </path>
040: *
041: * <typedef
042: * name="jmxCondition"
043: * classname="org.apache.catalina.ant.jmx.JMXAccessorCondition"
044: * classpathref="catalina_ant"/>
045: * <taskdef
046: * name="jmxOpen"
047: * classname="org.apache.catalina.ant.jmx.JMXAccessorTask"
048: * classpathref="catalina_ant"/>
049: * </pre>
050: *
051: * <b>Usage</b>: Wait for start backup node
052: * <pre>
053: * <target name="wait">
054: * <jmxOpen
055: * host="${jmx.host}" port="${jmx.port}" username="${jmx.username}" password="${jmx.password}" />
056: * <waitfor maxwait="${maxwait}" maxwaitunit="second" timeoutproperty="server.timeout" >
057: * <and>
058: * <socket server="${server.name}" port="${server.port}"/>
059: * <http url="${url}"/>
060: * <jmxCondition
061: * name="Catalina:type=IDataSender,host=localhost,senderAddress=192.168.111.1,senderPort=9025"
062: * operation="=="
063: * attribute="connected" value="true"
064: * />
065: * <jmxCondition
066: * operation="&lt;"
067: * name="Catalina:j2eeType=WebModule,name=//${tomcat.application.host}${tomcat.application.path},J2EEApplication=none,J2EEServer=none"
068: * attribute="startupTime" value="250"
069: * />
070: * </and>
071: * </waitfor>
072: * <fail if="server.timeout" message="Server ${url} don't answer inside ${maxwait} sec" />
073: * <echo message="Server ${url} alive" />
074: * </target>
075: *
076: * </pre>
077: * Allowed operation between jmx attribute and reference value:
078: * <ul>
079: * <li>== equals</li>
080: * <li>!= not equals</li>
081: * <li>> greater than (&gt;)</li>
082: * <li>>= greater than or equals (&gt;=)</li>
083: * <li>< lesser than (&lt;)</li>
084: * <li><= lesser than or equals (&lt;=)</li>
085: * </ul>
086: * <b>NOTE</b>: For numeric expressions the type must be set and use xml entities as operations.<br/>
087: * As type we currently support <em>long</em> and <em>double</em>.
088: * @author Peter Rossbach
089: * @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
090: * @since 5.5.10
091: *
092: */
093: public class JMXAccessorCondition extends ProjectComponent implements
094: Condition {
095:
096: // ----------------------------------------------------- Instance Variables
097:
098: private String url = null;
099: private String host = "localhost";
100: private String port = "8050";
101: private String password = null;
102: private String username = null;
103: private String name = null;
104: private String attribute;
105: private String value;
106: private String operation = "==";
107: private String type = "long";
108: private String ref = "jmx.server";
109: private String unlessCondition;
110: private String ifCondition;
111:
112: // ----------------------------------------------------- Instance Info
113:
114: /**
115: * Descriptive information describing this implementation.
116: */
117: private static final String info = "org.apache.catalina.ant.JMXAccessorCondition/1.1";
118:
119: /**
120: * Return descriptive information about this implementation and the
121: * corresponding version number, in the format
122: * <code><description>/<version></code>.
123: */
124: public String getInfo() {
125:
126: return (info);
127:
128: }
129:
130: // ----------------------------------------------------- Properties
131:
132: /**
133: * @return Returns the operation.
134: */
135: public String getOperation() {
136: return operation;
137: }
138:
139: /**
140: * @param operation The operation to set.
141: */
142: public void setOperation(String operation) {
143: this .operation = operation;
144: }
145:
146: /**
147: * @return Returns the type.
148: */
149: public String getType() {
150: return type;
151: }
152:
153: /**
154: * @param type The type to set.
155: */
156: public void setType(String type) {
157: this .type = type;
158: }
159:
160: /**
161: * @return Returns the attribute.
162: */
163: public String getAttribute() {
164: return attribute;
165: }
166:
167: /**
168: * @param attribute The attribute to set.
169: */
170: public void setAttribute(String attribute) {
171: this .attribute = attribute;
172: }
173:
174: /**
175: * @return Returns the host.
176: */
177: public String getHost() {
178: return host;
179: }
180:
181: /**
182: * @param host The host to set.
183: */
184: public void setHost(String host) {
185: this .host = host;
186: }
187:
188: /**
189: * @return Returns the name.
190: */
191: public String getName() {
192: return name;
193: }
194:
195: /**
196: * @param objectName The name to set.
197: */
198: public void setName(String objectName) {
199: this .name = objectName;
200: }
201:
202: /**
203: * @return Returns the password.
204: */
205: public String getPassword() {
206: return password;
207: }
208:
209: /**
210: * @param password The password to set.
211: */
212: public void setPassword(String password) {
213: this .password = password;
214: }
215:
216: /**
217: * @return Returns the port.
218: */
219: public String getPort() {
220: return port;
221: }
222:
223: /**
224: * @param port The port to set.
225: */
226: public void setPort(String port) {
227: this .port = port;
228: }
229:
230: /**
231: * @return Returns the url.
232: */
233: public String getUrl() {
234: return url;
235: }
236:
237: /**
238: * @param url The url to set.
239: */
240: public void setUrl(String url) {
241: this .url = url;
242: }
243:
244: /**
245: * @return Returns the username.
246: */
247: public String getUsername() {
248: return username;
249: }
250:
251: /**
252: * @param username The username to set.
253: */
254: public void setUsername(String username) {
255: this .username = username;
256: }
257:
258: /**
259: * @return Returns the value.
260: */
261: public String getValue() {
262: return value;
263: }
264:
265: // The setter for the "value" attribute
266: public void setValue(String value) {
267: this .value = value;
268: }
269:
270: /**
271: * @return Returns the ref.
272: */
273: public String getRef() {
274: return ref;
275: }
276:
277: /**
278: * @param refId The ref to set.
279: */
280: public void setRef(String refId) {
281: this .ref = refId;
282: }
283:
284: /**
285: * @return Returns the ifCondition.
286: */
287: public String getIf() {
288: return ifCondition;
289: }
290:
291: /**
292: * Only execute if a property of the given name exists in the current project.
293: * @param c property name
294: */
295: public void setIf(String c) {
296: ifCondition = c;
297: }
298:
299: /**
300: * @return Returns the unlessCondition.
301: */
302: public String getUnless() {
303: return unlessCondition;
304: }
305:
306: /**
307: * Only execute if a property of the given name does not
308: * exist in the current project.
309: * @param c property name
310: */
311: public void setUnless(String c) {
312: unlessCondition = c;
313: }
314:
315: /**
316: * Get JMXConnection (default look at <em>jmx.server</em> project reference from jmxOpen Task)
317: * @return active JMXConnection
318: * @throws MalformedURLException
319: * @throws IOException
320: */
321: protected MBeanServerConnection getJMXConnection()
322: throws MalformedURLException, IOException {
323: return JMXAccessorTask.accessJMXConnection(getProject(),
324: getUrl(), getHost(), getPort(), getUsername(),
325: getPassword(), ref);
326: }
327:
328: /**
329: * Get value from MBeans attribute
330: * @return The value
331: */
332: protected String accessJMXValue() {
333: try {
334: Object result = getJMXConnection().getAttribute(
335: new ObjectName(name), attribute);
336: if (result != null)
337: return result.toString();
338: } catch (Exception e) {
339: // ignore access or connection open errors
340: }
341: return null;
342: }
343:
344: /**
345: * test the if condition
346: * @return true if there is no if condition, or the named property exists
347: */
348: protected boolean testIfCondition() {
349: if (ifCondition == null || "".equals(ifCondition)) {
350: return true;
351: }
352: return getProject().getProperty(ifCondition) != null;
353: }
354:
355: /**
356: * test the unless condition
357: * @return true if there is no unless condition,
358: * or there is a named property but it doesn't exist
359: */
360: protected boolean testUnlessCondition() {
361: if (unlessCondition == null || "".equals(unlessCondition)) {
362: return true;
363: }
364: return getProject().getProperty(unlessCondition) == null;
365: }
366:
367: /**
368: * This method evaluates the condition
369: * It support for operation ">,>=,<,<=" the types <code>long</code> and <code>double</code>.
370: * @return expression <em>jmxValue</em> <em>operation</em> <em>value</em>
371: */
372: public boolean eval() {
373: if (operation == null) {
374: throw new BuildException("operation attribute is not set");
375: }
376: if (value == null) {
377: throw new BuildException("value attribute is not set");
378: }
379: if ((name == null || attribute == null)) {
380: throw new BuildException(
381: "Must specify a 'attribute', name for equals condition");
382: }
383: if (testIfCondition() && testUnlessCondition()) {
384: String jmxValue = accessJMXValue();
385: if (jmxValue != null) {
386: String op = getOperation();
387: if ("==".equals(op)) {
388: return jmxValue.equals(value);
389: } else if ("!=".equals(op)) {
390: return !jmxValue.equals(value);
391: } else {
392: if ("long".equals(type)) {
393: long jvalue = Long.parseLong(jmxValue);
394: long lvalue = Long.parseLong(value);
395: if (">".equals(op)) {
396: return jvalue > lvalue;
397: } else if (">=".equals(op)) {
398: return jvalue >= lvalue;
399: } else if ("<".equals(op)) {
400: return jvalue < lvalue;
401: } else if ("<=".equals(op)) {
402: return jvalue <= lvalue;
403: }
404: } else if ("double".equals(type)) {
405: double jvalue = Double.parseDouble(jmxValue);
406: double dvalue = Double.parseDouble(value);
407: if (">".equals(op)) {
408: return jvalue > dvalue;
409: } else if (">=".equals(op)) {
410: return jvalue >= dvalue;
411: } else if ("<".equals(op)) {
412: return jvalue < dvalue;
413: } else if ("<=".equals(op)) {
414: return jvalue <= dvalue;
415: }
416: }
417: }
418: }
419: return false;
420: }
421: return true;
422: }
423: }
|