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.mavenplugins.geronimo; 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 033 // 034 // FIXME: It should be possible to query state with-out any Geronimo classes, 035 // just using JMX interfaces. 036 // 037 038 import org.apache.geronimo.gbean.AbstractName; 039 import org.apache.geronimo.gbean.AbstractNameQuery; 040 import org.apache.geronimo.kernel.Kernel; 041 import org.apache.geronimo.kernel.config.PersistentConfigurationList; 042 043 import org.apache.commons.logging.Log; 044 import org.apache.commons.logging.LogFactory; 045 046 /** 047 * Helper to communicate with a remote server via JMX. 048 * 049 * @version $Rev: 442872 $ $Date: 2006-09-12 23:55:19 -0700 (Tue, 12 Sep 2006) $ 050 */ 051 public class ServerProxy 052 { 053 private static final Log log = LogFactory.getLog(ServerProxy.class); 054 055 private JMXServiceURL url; 056 057 private Map environment; 058 059 private MBeanServerConnection mbeanConnection; 060 061 private Throwable lastError; 062 063 public ServerProxy(final JMXServiceURL url, final Map environment) throws Exception { 064 init(url, environment); 065 } 066 067 public ServerProxy(final String hostname, final int port, final String username, final String password) throws Exception { 068 // 069 // TODO: Check if this is the right way to build up the URI 070 // 071 072 this("service:jmx:rmi://" + hostname + "/jndi/rmi://" + hostname + ":" + port + "/JMXConnector", username, password); 073 } 074 075 public ServerProxy(final String url, final String username, final String password) throws Exception { 076 assert url != null; 077 assert username != null; 078 assert password != null; 079 080 Map env = new HashMap(); 081 env.put("jmx.remote.credentials", new String[] {username, password}); 082 083 init(new JMXServiceURL(url), env); 084 } 085 086 private void init(final JMXServiceURL url, final Map environment) throws Exception { 087 assert url != null; 088 assert environment != null; 089 090 this.url = url; 091 this.environment = new HashMap(); 092 this.environment.put("jmx.remote.credentials", new String[] {"system", "manager"}); 093 094 log.debug("Initialized with URL: " + url + ", environment: " + environment); 095 } 096 097 private MBeanServerConnection getConnection() throws IOException { 098 if (this.mbeanConnection == null) { 099 log.debug("Connecting to: " + url); 100 101 JMXConnector connector = JMXConnectorFactory.connect(url, environment); 102 this.mbeanConnection = connector.getMBeanServerConnection(); 103 104 log.debug("Connected"); 105 } 106 107 return mbeanConnection; 108 } 109 110 public boolean isFullyStarted() { 111 boolean fullyStarted = true; 112 113 try { 114 AbstractNameQuery query = new AbstractNameQuery(PersistentConfigurationList.class.getName()); 115 Set result = listGBeans(query); 116 Iterator iter = result.iterator(); 117 while (iter.hasNext()) { 118 AbstractName name = (AbstractName)iter.next(); 119 boolean started = getBooleanAttribute(name, "kernelFullyStarted"); 120 if (!started) { 121 fullyStarted = false; 122 break; 123 } 124 } 125 } 126 catch (IOException e) { 127 log.debug("Connection failure; ignoring", e); 128 fullyStarted = false; 129 lastError = e; 130 } 131 catch (Exception e) { 132 log.debug("Unable to determine if the server is fully started", e); 133 fullyStarted = false; 134 lastError = e; 135 } 136 137 return fullyStarted; 138 } 139 140 public Throwable getLastError() { 141 return lastError; 142 } 143 144 public void shutdown() { 145 try { 146 invoke("shutdown"); 147 } 148 catch (Exception e) { 149 log.warn("Unable to shutdown the server", e); 150 lastError = e; 151 } 152 } 153 154 // 155 // Kernel invocation helpers 156 // 157 158 private Object invoke(final String operation, final Object[] args, final String[] signature) throws Exception { 159 assert operation != null; 160 assert args != null; 161 assert signature != null; 162 163 return getConnection().invoke(Kernel.KERNEL, operation, args, signature); 164 } 165 166 private Object invoke(final String operation, final Object[] args) throws Exception { 167 assert args != null; 168 169 String[] signature = new String[args.length]; 170 for (int i=0; i<args.length; i++) { 171 signature[i] = args[i].getClass().getName(); 172 } 173 174 return invoke(operation, args, signature); 175 } 176 177 private Object invoke(final String operation) throws Exception { 178 return invoke(operation, new Object[0]); 179 } 180 181 private Set listGBeans(final AbstractNameQuery query) throws Exception { 182 return (Set)invoke("listGBeans", new Object[] { query }); 183 } 184 185 private Object getAttribute(final AbstractName name, final String attribute) throws Exception { 186 assert name != null; 187 assert attribute != null; 188 189 return invoke("getAttribute", new Object[] { name, attribute }); 190 } 191 192 private boolean getBooleanAttribute(final AbstractName name, final String attribute) throws Exception { 193 Object obj = getAttribute(name, attribute); 194 if (obj instanceof Boolean) { 195 return ((Boolean)obj).booleanValue(); 196 } 197 else { 198 throw new RuntimeException("Attribute is not of type Boolean: " + attribute); 199 } 200 } 201 }