001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019:
020: package org.apache.geronimo.commands;
021:
022: import java.util.HashMap;
023: import java.util.Map;
024: import java.util.Set;
025: import java.util.Iterator;
026: import java.io.IOException;
027:
028: import javax.management.remote.JMXServiceURL;
029: import javax.management.remote.JMXConnector;
030: import javax.management.remote.JMXConnectorFactory;
031: import javax.management.MBeanServerConnection;
032: import javax.management.ObjectName;
033:
034: //
035: // FIXME: It should be possible to query state with-out any Geronimo classes,
036: // just using JMX interfaces.
037: //
038:
039: import org.apache.geronimo.gbean.AbstractName;
040: import org.apache.geronimo.gbean.AbstractNameQuery;
041: import org.apache.geronimo.kernel.Kernel;
042: import org.apache.geronimo.kernel.config.PersistentConfigurationList;
043:
044: import org.slf4j.Logger;
045: import org.slf4j.LoggerFactory;
046:
047: /**
048: * Helper to communicate with a remote server via JMX.
049: *
050: * @version $Rev: 630982 $ $Date: 2008-02-25 12:30:54 -0800 (Mon, 25 Feb 2008) $
051: */
052: public class ServerProxy {
053: private static final Logger log = LoggerFactory
054: .getLogger(ServerProxy.class);
055:
056: private JMXServiceURL url;
057:
058: private Map environment;
059:
060: private MBeanServerConnection mbeanConnection;
061:
062: private Throwable lastError;
063:
064: public ServerProxy(final JMXServiceURL url, final Map environment)
065: throws Exception {
066: assert url != null;
067: assert environment != null;
068:
069: this .url = url;
070: this .environment = environment;
071:
072: log.debug("Initialized with URL: " + url + ", environment: "
073: + environment);
074: }
075:
076: public ServerProxy(final String hostname, final int port,
077: final String username, final String password)
078: throws Exception {
079: this ("service:jmx:rmi://" + hostname + "/jndi/rmi://"
080: + hostname + ":" + port + "/JMXConnector", username,
081: password);
082: }
083:
084: public ServerProxy(final String url, final String username,
085: final String password) throws Exception {
086: assert url != null;
087: assert username != null;
088: assert password != null;
089:
090: this .url = new JMXServiceURL(url);
091: this .environment = new HashMap();
092: this .environment.put("jmx.remote.credentials", new String[] {
093: username, password });
094:
095: log.debug("Initialized with URL: " + url + ", environment: "
096: + environment);
097: }
098:
099: public ServerProxy(JMXConnector connector) throws Exception {
100: this .mbeanConnection = connector.getMBeanServerConnection();
101: }
102:
103: private MBeanServerConnection getConnection() throws IOException {
104: if (this .mbeanConnection == null) {
105: log.debug("Connecting to: " + url);
106:
107: JMXConnector connector = JMXConnectorFactory.connect(url,
108: environment);
109: this .mbeanConnection = connector.getMBeanServerConnection();
110:
111: log.debug("Connected");
112: }
113:
114: return mbeanConnection;
115: }
116:
117: public boolean isFullyStarted() {
118: boolean fullyStarted = true;
119:
120: try {
121: AbstractNameQuery query = new AbstractNameQuery(
122: PersistentConfigurationList.class.getName());
123: Set result = listGBeans(query);
124: Iterator iter = result.iterator();
125: while (iter.hasNext()) {
126: AbstractName name = (AbstractName) iter.next();
127: boolean started = getBooleanAttribute(name,
128: "kernelFullyStarted");
129: if (!started) {
130: fullyStarted = false;
131: break;
132: }
133: }
134: } catch (IOException e) {
135: String msg = "Connection failure; ignoring";
136: if (log.isTraceEnabled()) {
137: log.trace(msg, e);
138: } else if (log.isDebugEnabled()) {
139: log.debug(msg + ": " + e);
140: }
141:
142: fullyStarted = false;
143: lastError = e;
144: } catch (Exception e) {
145: String msg = "Unable to determine if the server is fully started; ignoring";
146: if (log.isTraceEnabled()) {
147: log.trace(msg, e);
148: } else if (log.isDebugEnabled()) {
149: log.debug(msg + ": " + e);
150: }
151:
152: fullyStarted = false;
153: lastError = e;
154: }
155:
156: return fullyStarted;
157: }
158:
159: public String getGeronimoHome() {
160: String home = null;
161:
162: try {
163: ObjectName systemInfoQuery = new ObjectName(
164: "*:name=ServerInfo,j2eeType=GBean,*");
165:
166: getConnection();
167:
168: Set set = mbeanConnection.queryNames(systemInfoQuery, null);
169:
170: if (set.size() > 0) {
171: ObjectName found = (ObjectName) set.iterator().next();
172: home = (String) mbeanConnection.getAttribute(found,
173: "currentBaseDirectory");
174: }
175: } catch (IOException e) {
176: String msg = "Connection failure; ignoring";
177: if (log.isTraceEnabled()) {
178: log.trace(msg, e);
179: } else if (log.isDebugEnabled()) {
180: log.debug(msg + ": " + e);
181: }
182:
183: lastError = e;
184: } catch (Exception e) {
185: String msg = "Unable to determine if the server is fully started; ignoring";
186: if (log.isTraceEnabled()) {
187: log.trace(msg, e);
188: } else if (log.isDebugEnabled()) {
189: log.debug(msg + ": " + e);
190: }
191:
192: lastError = e;
193: }
194:
195: return home;
196: }
197:
198: public Throwable getLastError() {
199: return lastError;
200: }
201:
202: public void shutdown() {
203: try {
204: invoke("shutdown");
205: } catch (Exception e) {
206: log.warn("Unable to shutdown the server", e);
207: lastError = e;
208: }
209: }
210:
211: //
212: // Kernel invocation helpers
213: //
214:
215: private Object invoke(final String operation, final Object[] args,
216: final String[] signature) throws Exception {
217: assert operation != null;
218: assert args != null;
219: assert signature != null;
220:
221: return getConnection().invoke(Kernel.KERNEL, operation, args,
222: signature);
223: }
224:
225: private Object invoke(final String operation, final Object[] args)
226: throws Exception {
227: assert args != null;
228:
229: String[] signature = new String[args.length];
230: for (int i = 0; i < args.length; i++) {
231: signature[i] = args[i].getClass().getName();
232: }
233:
234: return invoke(operation, args, signature);
235: }
236:
237: private Object invoke(final String operation) throws Exception {
238: return invoke(operation, new Object[0]);
239: }
240:
241: private Set listGBeans(final AbstractNameQuery query)
242: throws Exception {
243: return (Set) invoke("listGBeans", new Object[] { query });
244: }
245:
246: private Object getAttribute(final AbstractName name,
247: final String attribute) throws Exception {
248: assert name != null;
249: assert attribute != null;
250:
251: return invoke("getAttribute", new Object[] { name, attribute });
252: }
253:
254: private boolean getBooleanAttribute(final AbstractName name,
255: final String attribute) throws Exception {
256: Object obj = getAttribute(name, attribute);
257: if (obj instanceof Boolean) {
258: return ((Boolean) obj).booleanValue();
259: } else {
260: throw new RuntimeException(
261: "Attribute is not of type Boolean: " + attribute);
262: }
263: }
264: }
|