1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.catalina.ant.jmx;
19
20 import java.io.IOException;
21 import java.net.MalformedURLException;
22
23 import javax.management.MBeanServerConnection;
24 import javax.management.ObjectName;
25
26 import org.apache.tools.ant.BuildException;
27 import org.apache.tools.ant.ProjectComponent;
28 import org.apache.tools.ant.taskdefs.condition.Condition;
29
30 /**
31 *
32 * <b>Definition</b>:
33 * <pre>
34 * <path id="catalina_ant">
35 * <fileset dir="${catalina.home}/server/lib">
36 * <include name="catalina-ant.jar"/>
37 * </fileset>
38 * </path>
39 *
40 * <typedef
41 * name="jmxCondition"
42 * classname="org.apache.catalina.ant.jmx.JMXAccessorCondition"
43 * classpathref="catalina_ant"/>
44 * <taskdef
45 * name="jmxOpen"
46 * classname="org.apache.catalina.ant.jmx.JMXAccessorTask"
47 * classpathref="catalina_ant"/>
48 * </pre>
49 *
50 * <b>Usage</b>: Wait for start backup node
51 * <pre>
52 * <target name="wait">
53 * <jmxOpen
54 * host="${jmx.host}" port="${jmx.port}" username="${jmx.username}" password="${jmx.password}" />
55 * <waitfor maxwait="${maxwait}" maxwaitunit="second" timeoutproperty="server.timeout" >
56 * <and>
57 * <socket server="${server.name}" port="${server.port}"/>
58 * <http url="${url}"/>
59 * <jmxCondition
60 * name="Catalina:type=IDataSender,host=localhost,senderAddress=192.168.111.1,senderPort=9025"
61 * operation="=="
62 * attribute="connected" value="true"
63 * />
64 * <jmxCondition
65 * operation="&lt;"
66 * name="Catalina:j2eeType=WebModule,name=//${tomcat.application.host}${tomcat.application.path},J2EEApplication=none,J2EEServer=none"
67 * attribute="startupTime" value="250"
68 * />
69 * </and>
70 * </waitfor>
71 * <fail if="server.timeout" message="Server ${url} don't answer inside ${maxwait} sec" />
72 * <echo message="Server ${url} alive" />
73 * </target>
74 *
75 * </pre>
76 * Allowed operation between jmx attribute and reference value:
77 * <ul>
78 * <li>== equals</li>
79 * <li>!= not equals</li>
80 * <li>> greater than (&gt;)</li>
81 * <li>>= greater than or equals (&gt;=)</li>
82 * <li>< lesser than (&lt;)</li>
83 * <li><= lesser than or equals (&lt;=)</li>
84 * </ul>
85 * <b>NOTE</b>: For numeric expressions the type must be set and use xml entities as operations.<br/>
86 * As type we currently support <em>long</em> and <em>double</em>.
87 * @author Peter Rossbach
88 * @version $Revision: 612599 $ $Date: 2008-01-16 23:37:36 +0100 (mer., 16 janv. 2008) $
89 * @since 5.5.10
90 *
91 */
92 public class JMXAccessorCondition extends ProjectComponent implements Condition {
93
94 // ----------------------------------------------------- Instance Variables
95
96 private String url = null;
97 private String host = "localhost";
98 private String port = "8050";
99 private String password = null;
100 private String username = null;
101 private String name = null;
102 private String attribute;
103 private String value;
104 private String operation = "==" ;
105 private String type = "long" ;
106 private String ref = "jmx.server";
107 private String unlessCondition;
108 private String ifCondition;
109
110 // ----------------------------------------------------- Instance Info
111
112 /**
113 * Descriptive information describing this implementation.
114 */
115 private static final String info = "org.apache.catalina.ant.JMXAccessorCondition/1.1";
116
117 /**
118 * Return descriptive information about this implementation and the
119 * corresponding version number, in the format
120 * <code><description>/<version></code>.
121 */
122 public String getInfo() {
123
124 return (info);
125
126 }
127 // ----------------------------------------------------- Properties
128
129 /**
130 * @return Returns the operation.
131 */
132 public String getOperation() {
133 return operation;
134 }
135 /**
136 * @param operation The operation to set.
137 */
138 public void setOperation(String operation) {
139 this.operation = operation;
140 }
141
142 /**
143 * @return Returns the type.
144 */
145 public String getType() {
146 return type;
147 }
148 /**
149 * @param type The type to set.
150 */
151 public void setType(String type) {
152 this.type = type;
153 }
154 /**
155 * @return Returns the attribute.
156 */
157 public String getAttribute() {
158 return attribute;
159 }
160 /**
161 * @param attribute The attribute to set.
162 */
163 public void setAttribute(String attribute) {
164 this.attribute = attribute;
165 }
166 /**
167 * @return Returns the host.
168 */
169 public String getHost() {
170 return host;
171 }
172 /**
173 * @param host The host to set.
174 */
175 public void setHost(String host) {
176 this.host = host;
177 }
178 /**
179 * @return Returns the name.
180 */
181 public String getName() {
182 return name;
183 }
184 /**
185 * @param objectName The name to set.
186 */
187 public void setName(String objectName) {
188 this.name = objectName;
189 }
190 /**
191 * @return Returns the password.
192 */
193 public String getPassword() {
194 return password;
195 }
196 /**
197 * @param password The password to set.
198 */
199 public void setPassword(String password) {
200 this.password = password;
201 }
202 /**
203 * @return Returns the port.
204 */
205 public String getPort() {
206 return port;
207 }
208 /**
209 * @param port The port to set.
210 */
211 public void setPort(String port) {
212 this.port = port;
213 }
214 /**
215 * @return Returns the url.
216 */
217 public String getUrl() {
218 return url;
219 }
220 /**
221 * @param url The url to set.
222 */
223 public void setUrl(String url) {
224 this.url = url;
225 }
226 /**
227 * @return Returns the username.
228 */
229 public String getUsername() {
230 return username;
231 }
232 /**
233 * @param username The username to set.
234 */
235 public void setUsername(String username) {
236 this.username = username;
237 }
238 /**
239 * @return Returns the value.
240 */
241 public String getValue() {
242 return value;
243 }
244 // The setter for the "value" attribute
245 public void setValue(String value) {
246 this.value = value;
247 }
248
249 /**
250 * @return Returns the ref.
251 */
252 public String getRef() {
253 return ref;
254 }
255 /**
256 * @param refId The ref to set.
257 */
258 public void setRef(String refId) {
259 this.ref = refId;
260 }
261 /**
262 * @return Returns the ifCondition.
263 */
264 public String getIf() {
265 return ifCondition;
266 }
267 /**
268 * Only execute if a property of the given name exists in the current project.
269 * @param c property name
270 */
271 public void setIf(String c) {
272 ifCondition = c;
273 }
274 /**
275 * @return Returns the unlessCondition.
276 */
277 public String getUnless() {
278 return unlessCondition;
279 }
280
281 /**
282 * Only execute if a property of the given name does not
283 * exist in the current project.
284 * @param c property name
285 */
286 public void setUnless(String c) {
287 unlessCondition = c;
288 }
289
290 /**
291 * Get JMXConnection (default look at <em>jmx.server</em> project reference from jmxOpen Task)
292 * @return active JMXConnection
293 * @throws MalformedURLException
294 * @throws IOException
295 */
296 protected MBeanServerConnection getJMXConnection()
297 throws MalformedURLException, IOException {
298 return JMXAccessorTask.accessJMXConnection(
299 getProject(),
300 getUrl(), getHost(),
301 getPort(), getUsername(), getPassword(), ref);
302 }
303
304 /**
305 * Get value from MBeans attribute
306 * @return The value
307 */
308 protected String accessJMXValue() {
309 try {
310 Object result = getJMXConnection().getAttribute(
311 new ObjectName(name), attribute);
312 if(result != null)
313 return result.toString();
314 } catch (Exception e) {
315 // ignore access or connection open errors
316 }
317 return null;
318 }
319
320 /**
321 * test the if condition
322 * @return true if there is no if condition, or the named property exists
323 */
324 protected boolean testIfCondition() {
325 if (ifCondition == null || "".equals(ifCondition)) {
326 return true;
327 }
328 return getProject().getProperty(ifCondition) != null;
329 }
330
331 /**
332 * test the unless condition
333 * @return true if there is no unless condition,
334 * or there is a named property but it doesn't exist
335 */
336 protected boolean testUnlessCondition() {
337 if (unlessCondition == null || "".equals(unlessCondition)) {
338 return true;
339 }
340 return getProject().getProperty(unlessCondition) == null;
341 }
342
343 /**
344 * This method evaluates the condition
345 * It support for operation ">,>=,<,<=" the types <code>long</code> and <code>double</code>.
346 * @return expression <em>jmxValue</em> <em>operation</em> <em>value</em>
347 */
348 public boolean eval() {
349 if (operation == null) {
350 throw new BuildException("operation attribute is not set");
351 }
352 if (value == null) {
353 throw new BuildException("value attribute is not set");
354 }
355 if ((name == null || attribute == null)) {
356 throw new BuildException(
357 "Must specify a 'attribute', name for equals condition");
358 }
359 if (testIfCondition() && testUnlessCondition()) {
360 String jmxValue = accessJMXValue();
361 if (jmxValue != null) {
362 String op = getOperation();
363 if ("==".equals(op)) {
364 return jmxValue.equals(value);
365 } else if ("!=".equals(op)) {
366 return !jmxValue.equals(value);
367 } else {
368 if ("long".equals(type)) {
369 long jvalue = Long.parseLong(jmxValue);
370 long lvalue = Long.parseLong(value);
371 if (">".equals(op)) {
372 return jvalue > lvalue;
373 } else if (">=".equals(op)) {
374 return jvalue >= lvalue;
375 } else if ("<".equals(op)) {
376 return jvalue < lvalue;
377 } else if ("<=".equals(op)) {
378 return jvalue <= lvalue;
379 }
380 } else if ("double".equals(type)) {
381 double jvalue = Double.parseDouble(jmxValue);
382 double dvalue = Double.parseDouble(value);
383 if (">".equals(op)) {
384 return jvalue > dvalue;
385 } else if (">=".equals(op)) {
386 return jvalue >= dvalue;
387 } else if ("<".equals(op)) {
388 return jvalue < dvalue;
389 } else if ("<=".equals(op)) {
390 return jvalue <= dvalue;
391 }
392 }
393 }
394 }
395 return false;
396 }
397 return true;
398 }
399 }
400