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.geronimo.deployment.plugin.factories;
019    
020    import java.io.IOException;
021    import java.util.Collection;
022    import java.util.Collections;
023    import java.util.HashMap;
024    import java.util.Map;
025    
026    import javax.enterprise.deploy.spi.DeploymentManager;
027    import javax.enterprise.deploy.spi.exceptions.DeploymentManagerCreationException;
028    import javax.enterprise.deploy.spi.factories.DeploymentFactory;
029    import javax.management.remote.JMXConnector;
030    import javax.management.remote.JMXConnectorFactory;
031    import javax.management.remote.JMXServiceURL;
032    import javax.management.remote.rmi.RMIConnectorServer;
033    import javax.rmi.ssl.SslRMIClientSocketFactory;
034    
035    import org.apache.commons.logging.Log;
036    import org.apache.commons.logging.LogFactory;
037    import org.apache.geronimo.deployment.ModuleConfigurer;
038    import org.apache.geronimo.deployment.plugin.DisconnectedDeploymentManager;
039    import org.apache.geronimo.deployment.plugin.jmx.LocalDeploymentManager;
040    import org.apache.geronimo.deployment.plugin.jmx.RemoteDeploymentManager;
041    import org.apache.geronimo.kernel.KernelRegistry;
042    
043    /**
044     * Base implementation of JSR88 DeploymentFactory.
045     *
046     * This will create a DeploymentManager using a local Geronimo kernel
047     * to contain the GBeans that are responsible for deploying each module
048     * type.
049     *
050     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
051     */
052    public class BaseDeploymentFactory implements DeploymentFactory {
053        private static final Log log = LogFactory.getLog(BaseDeploymentFactory.class);
054    
055        public static final String URI_PREFIX = "deployer:geronimo:";
056        private static final int DEFAULT_PORT = 1099;
057    
058        public BaseDeploymentFactory() {
059        }
060    
061        public String getDisplayName() {
062            return "Apache Geronimo";
063        }
064    
065        public String getProductVersion() {
066            return "1.0";
067        }
068    
069        public boolean handlesURI(String uri) {
070            return parseURI(uri) != null;
071        }
072    
073        private ConnectParams parseURI(String uri) {
074            uri = uri.trim();
075            if (log.isDebugEnabled()) {
076                log.debug("Parsing URI=" + uri);
077            }
078            if(!uri.startsWith(URI_PREFIX)) {
079                return null;
080            }
081            uri = uri.substring(URI_PREFIX.length());
082            int pos = uri.indexOf(":");
083            String protocol = pos == -1 ? uri : uri.substring(0, pos);
084            uri = pos == -1 ? "" : uri.substring(pos+1);
085            if(protocol.equals("jmx") || protocol.equals("jmxs")) {
086                boolean secure = protocol.equals("jmxs");
087                if(!uri.startsWith("//")) {
088                    return new ConnectParams(protocol, "localhost", DEFAULT_PORT, secure);
089                }
090                uri = uri.substring(2);
091                pos = uri.indexOf(':');
092                if(pos == -1) {
093                    return new ConnectParams(protocol, uri.equals("") ? "localhost" : uri, DEFAULT_PORT, secure);
094                }
095                if(uri.indexOf('/', pos+1) > -1) {
096                    return null;
097                }
098                if(uri.indexOf(':', pos+1) > -1) {
099                    return null;
100                }
101                String host = uri.substring(0, pos);
102                String port = uri.substring(pos+1);
103                try {
104                    return new ConnectParams(protocol, host.equals("") ? "localhost" : host, Integer.parseInt(port), secure);
105                } catch (NumberFormatException e) {
106                    return null;
107                }
108            } else if(protocol.equals("inVM")) {
109                if(uri.startsWith("//")) {
110                    String kernel = uri.substring(2);
111                    return new ConnectParams(protocol, kernel, -1);
112                } else {
113                    return new ConnectParams(protocol,
114                            KernelRegistry.getSingleKernel() == null ? null : KernelRegistry.getSingleKernel().getKernelName(),
115                            -1);
116                }
117            } else return null;
118        }
119    
120        public DeploymentManager getDisconnectedDeploymentManager(String uri) throws DeploymentManagerCreationException {
121            if (!handlesURI(uri)) {
122                return null;
123            }
124            
125            Collection<ModuleConfigurer> moduleConfigurers = getModuleConfigurers();
126            return new DisconnectedDeploymentManager(moduleConfigurers);
127        }
128    
129        public DeploymentManager getDeploymentManager(String uri, String username, String password) throws DeploymentManagerCreationException {
130            ConnectParams params = parseURI(uri);
131            if (params == null) {
132                return null;
133            }
134            if (log.isDebugEnabled()) {
135                log.debug("Using protocol=" + params.getProtocol() + ", host=" + params.getHost() + ", port=" + params.getPort());
136            }
137    
138            try {
139                if (params.getProtocol().equals("jmx") || params.getProtocol().equals("jmxs")) {
140                    return newRemoteDeploymentManager(username, password, params);
141                } else if(params.getProtocol().equals("inVM")) {
142                    return new LocalDeploymentManager(KernelRegistry.getKernel(params.getHost()));
143                } else {
144                    throw new DeploymentManagerCreationException("Invalid URI: " + uri);
145                }
146            } catch (RuntimeException e) {
147                // some DeploymentManagerFactories suppress unchecked exceptions - log and rethrow
148                log.error(e.getMessage(), e);
149                throw e;
150            } catch (Error e) {
151                // some DeploymentManagerFactories suppress unchecked exceptions - log and rethrow
152                log.error(e.getMessage(), e);
153                throw e;
154            }
155        }
156    
157        protected Collection<ModuleConfigurer> getModuleConfigurers() throws DeploymentManagerCreationException {
158            return Collections.EMPTY_LIST;
159        }
160    
161        protected DeploymentManager newRemoteDeploymentManager(String username, String password, ConnectParams params) throws DeploymentManagerCreationException, AuthenticationFailedException {
162            Map environment = new HashMap();
163            String[] credentials = new String[]{username, password};
164            environment.put(JMXConnector.CREDENTIALS, credentials);
165            environment.put(JMXConnectorFactory.DEFAULT_CLASS_LOADER, BaseDeploymentFactory.class.getClassLoader());
166            String connectorName = "/JMXConnector";
167            if (params.isSecure()) {
168                connectorName = "/JMXSecureConnector";
169                SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory();
170                environment.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf);
171            }    
172            try {
173                // if ipv6 numeric address wrap with "[" "]"
174                String host = params.getHost();
175                if (host.indexOf(":") >= 0) {
176                    host = "[" + host + "]";
177                }
178                if (log.isDebugEnabled()) {
179                    log.debug("Using JMXServiceURL with host=" + host + ", port=" + params.getPort() + ", secure=" + params.isSecure());
180                }
181                JMXServiceURL address = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://"+ host +":"+params.getPort()+connectorName);
182                JMXConnector jmxConnector = JMXConnectorFactory.connect(address, environment);
183                RemoteDeploymentManager manager = getRemoteDeploymentManager();
184                manager.init(jmxConnector, host);
185                if(!manager.isSameMachine()) {
186                    manager.setAuthentication(username, password);
187                }
188                return manager;
189            } catch (IOException e) {
190                DeploymentManagerCreationException deploymentManagerCreationException = 
191                        (DeploymentManagerCreationException) new DeploymentManagerCreationException(e.getMessage()).initCause(e);
192                log.debug("throwing ", deploymentManagerCreationException);
193                throw deploymentManagerCreationException;
194            } catch (SecurityException e) {
195                AuthenticationFailedException authenticationFailedException = 
196                        (AuthenticationFailedException) new AuthenticationFailedException("Invalid login.").initCause(e);
197                log.debug("throwing ", authenticationFailedException);
198                throw authenticationFailedException;
199            }
200        }
201    
202        protected RemoteDeploymentManager getRemoteDeploymentManager() throws DeploymentManagerCreationException {
203            Collection<ModuleConfigurer> moduleConfigurers = getModuleConfigurers();
204            return new RemoteDeploymentManager(moduleConfigurers);
205        }
206    
207        private final static class ConnectParams {
208            private String protocol;
209            private String host;
210            private int port;
211            private boolean secure;
212    
213            public ConnectParams(String protocol, String host, int port) {
214                this(protocol, host, port, false);
215            }
216            
217            public ConnectParams(String protocol, String host, int port, boolean secure) {
218                this.protocol = protocol;
219                this.host = host;
220                this.port = port;
221                this.secure = secure;
222            }
223    
224            public String getProtocol() {
225                return protocol;
226            }
227    
228            public String getHost() {
229                return host;
230            }
231    
232            public int getPort() {
233                return port;
234            }
235    
236            public boolean isSecure() {
237                return secure;
238            }
239            
240            public String toString() {
241                return protocol+" / "+host+" / "+port;
242            }
243        }
244    
245    }