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    package org.apache.geronimo.deployment.plugin.jmx;
018    
019    import java.io.File;
020    import java.io.IOException;
021    import java.io.InputStream;
022    import java.net.InetAddress;
023    import java.net.NetworkInterface;
024    import java.net.URL;
025    import java.util.ArrayList;
026    import java.util.Collection;
027    import java.util.Enumeration;
028    import java.util.List;
029    import java.util.Map;
030    import java.util.Set;
031    
032    import javax.enterprise.deploy.shared.CommandType;
033    import javax.enterprise.deploy.shared.ModuleType;
034    import javax.enterprise.deploy.spi.Target;
035    import javax.enterprise.deploy.spi.TargetModuleID;
036    import javax.enterprise.deploy.spi.status.ProgressEvent;
037    import javax.enterprise.deploy.spi.status.ProgressListener;
038    import javax.management.MBeanServerConnection;
039    import javax.management.remote.JMXConnector;
040    import javax.security.auth.login.FailedLoginException;
041    
042    import org.apache.commons.logging.Log;
043    import org.apache.commons.logging.LogFactory;
044    import org.apache.geronimo.deployment.ModuleConfigurer;
045    import org.apache.geronimo.deployment.plugin.GeronimoDeploymentManager;
046    import org.apache.geronimo.deployment.plugin.local.AbstractDeployCommand;
047    import org.apache.geronimo.deployment.plugin.local.DistributeCommand;
048    import org.apache.geronimo.deployment.plugin.local.RedeployCommand;
049    import org.apache.geronimo.deployment.plugin.remote.RemoteDeployUtil;
050    import org.apache.geronimo.gbean.AbstractName;
051    import org.apache.geronimo.gbean.AbstractNameQuery;
052    import org.apache.geronimo.gbean.GBeanInfo;
053    import org.apache.geronimo.gbean.GBeanInfoBuilder;
054    import org.apache.geronimo.kernel.config.NoSuchStoreException;
055    import org.apache.geronimo.kernel.repository.Artifact;
056    import org.apache.geronimo.kernel.repository.Dependency;
057    import org.apache.geronimo.kernel.repository.MissingDependencyException;
058    import org.apache.geronimo.kernel.InvalidGBeanException;
059    import org.apache.geronimo.system.jmx.KernelDelegate;
060    import org.apache.geronimo.system.plugin.DownloadPoller;
061    import org.apache.geronimo.system.plugin.DownloadResults;
062    import org.apache.geronimo.system.plugin.PluginInstaller;
063    import org.apache.geronimo.system.plugin.PluginRepositoryList;
064    import org.apache.geronimo.system.plugin.ServerArchiver;
065    import org.apache.geronimo.system.plugin.model.PluginListType;
066    import org.apache.geronimo.system.plugin.model.PluginType;
067    import org.apache.geronimo.system.plugin.model.AttributesType;
068    import org.codehaus.plexus.archiver.ArchiverException;
069    
070    /**
071     * Connects to a Kernel in a remote VM (may or many not be on the same machine).
072     *
073     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
074     */
075    public class RemoteDeploymentManager extends JMXDeploymentManager implements GeronimoDeploymentManager, ServerArchiver {
076        private static final Log log = LogFactory.getLog(RemoteDeploymentManager.class);
077    
078        private JMXConnector jmxConnector;
079        private boolean isSameMachine;
080    
081        public RemoteDeploymentManager(Collection<ModuleConfigurer> moduleConfigurers) {
082            super(moduleConfigurers);
083        }
084    
085        public void init(JMXConnector jmxConnector, String hostname) throws IOException {
086            this.jmxConnector = jmxConnector;
087            MBeanServerConnection mbServerConnection = jmxConnector.getMBeanServerConnection();
088            initialize(new KernelDelegate(mbServerConnection));
089            checkSameMachine(hostname);
090        }
091    
092        public JMXConnector getJMXConnector() {
093            return this.jmxConnector;
094        }
095        
096        public boolean isSameMachine() {
097            return isSameMachine;
098        }
099    
100        private void checkSameMachine(String hostname) {
101            isSameMachine = false;
102            if (hostname.equals("localhost") || hostname.equals("127.0.0.1")) {
103                isSameMachine = true;
104                return;
105            }
106            try {
107                InetAddress dest = InetAddress.getByName(hostname);
108                Enumeration en = NetworkInterface.getNetworkInterfaces();
109                while (en.hasMoreElements()) {
110                    NetworkInterface iface = (NetworkInterface) en.nextElement();
111                    Enumeration ine = iface.getInetAddresses();
112                    while (ine.hasMoreElements()) {
113                        InetAddress address = (InetAddress) ine.nextElement();
114                        if (address.equals(dest)) {
115                            isSameMachine = true;
116                        }
117                    }
118                }
119            } catch (Exception e) {
120                log.error(
121                        "Unable to look up host name '" + hostname + "'; assuming it is a different machine, but this may not get very far.",
122                        e);
123            }
124        }
125    
126        public void release() {
127            super.release();
128            try {
129                jmxConnector.close();
130                jmxConnector = null;
131            } catch (IOException e) {
132                throw (IllegalStateException) new IllegalStateException("Unable to close connection").initCause(e);
133            }
134        }
135    
136        protected DistributeCommand createDistributeCommand(Target[] targetList, File moduleArchive, File deploymentPlan) {
137            if (isSameMachine) {
138                return super.createDistributeCommand(targetList, moduleArchive, deploymentPlan);
139            } else {
140                return new org.apache.geronimo.deployment.plugin.remote.DistributeCommand(kernel, targetList, moduleArchive,
141                        deploymentPlan);
142            }
143        }
144    
145        protected DistributeCommand createDistributeCommand(Target[] targetList, ModuleType moduleType, InputStream moduleArchive, InputStream deploymentPlan) {
146            if (isSameMachine) {
147                return super.createDistributeCommand(targetList, moduleType, moduleArchive, deploymentPlan);
148            } else {
149                return new org.apache.geronimo.deployment.plugin.remote.DistributeCommand(kernel, targetList, moduleType,
150                        moduleArchive, deploymentPlan);
151            }
152        }
153    
154        protected RedeployCommand createRedeployCommand(TargetModuleID[] moduleIDList, File moduleArchive, File deploymentPlan) {
155            if (isSameMachine) {
156                return super.createRedeployCommand(moduleIDList, moduleArchive, deploymentPlan);
157            } else {
158                return new org.apache.geronimo.deployment.plugin.remote.RedeployCommand(kernel, moduleIDList, moduleArchive,
159                        deploymentPlan);
160            }
161        }
162    
163        protected RedeployCommand createRedeployCommand(TargetModuleID[] moduleIDList, InputStream moduleArchive, InputStream deploymentPlan) {
164            if (isSameMachine) {
165                return super.createRedeployCommand(moduleIDList, moduleArchive, deploymentPlan);
166            } else {
167                return new org.apache.geronimo.deployment.plugin.remote.RedeployCommand(kernel, moduleIDList, moduleArchive,
168                        deploymentPlan);
169            }
170        }
171    
172        public PluginListType listPlugins(URL mavenRepository, String username, String password) throws FailedLoginException, IOException {
173            PluginInstaller installer = getPluginInstaller();
174            try {
175                return installer.listPlugins(mavenRepository, username, password);
176            } finally {
177                kernel.getProxyManager().destroyProxy(installer);
178            }
179        }
180        
181        public void validatePlugin(PluginType plugin) throws MissingDependencyException {
182            PluginInstaller installer = getPluginInstaller();
183            try {
184                installer.validatePlugin(plugin);
185            } finally {
186                kernel.getProxyManager().destroyProxy(installer);
187            }
188        }
189    
190        public Dependency[] checkPrerequisites(PluginType plugin) {
191            PluginInstaller installer = getPluginInstaller();
192            try {
193                return installer.checkPrerequisites(plugin);
194            } finally {
195                kernel.getProxyManager().destroyProxy(installer);
196            }
197        }
198    
199    
200        public DownloadResults install(PluginListType configsToInstall, String defaultRepository, boolean restrictToDefaultRepository, String username, String password) {
201            PluginInstaller installer = getPluginInstaller();
202            try {
203                return installer.install(configsToInstall, defaultRepository, restrictToDefaultRepository, username, password);
204            } finally {
205                kernel.getProxyManager().destroyProxy(installer);
206            }
207        }
208    
209        public void install(PluginListType configsToInstall, String defaultRepository, boolean restrictToDefaultRepository, String username, String password, DownloadPoller poller) {
210            PluginInstaller installer = getPluginInstaller();
211            try {
212                installer.install(configsToInstall, defaultRepository, restrictToDefaultRepository, username, password, poller);
213            } finally {
214                kernel.getProxyManager().destroyProxy(installer);
215            }
216        }
217    
218        public Object startInstall(PluginListType configsToInstall, String defaultRepository, boolean restrictToDefaultRepository, String username, String password) {
219            PluginInstaller installer = getPluginInstaller();
220            try {
221                return installer.startInstall(configsToInstall, defaultRepository, restrictToDefaultRepository, username, password);
222            } finally {
223                kernel.getProxyManager().destroyProxy(installer);
224            }
225        }
226    
227        public Object startInstall(File carFile, String defaultRepository, boolean restrictToDefaultRepository, String username, String password) {
228            File[] args = new File[]{carFile};
229            if (!isSameMachine) {
230                AbstractDeployCommand progress = new AbstractDeployCommand(CommandType.DISTRIBUTE, kernel, null, null, null,
231                        null, null, false) {
232                    public void run() {
233                    }
234                };
235                progress.addProgressListener(new ProgressListener() {
236                    public void handleProgressEvent(ProgressEvent event) {
237                        log.info(event.getDeploymentStatus().getMessage());
238                    }
239                });
240                progress.setCommandContext(commandContext);
241                RemoteDeployUtil.uploadFilesToServer(args, progress);
242            }
243            PluginInstaller installer = getPluginInstaller();
244            try {
245                // make sure to pass args[0] as RemoteDeployUtil.uploadFilesToServer will update
246                // the args argument with the filenames returned from the server
247                return installer.startInstall(args[0], defaultRepository, restrictToDefaultRepository, username, password);
248            } finally {
249                kernel.getProxyManager().destroyProxy(installer);
250            }
251        }
252    
253        public DownloadResults checkOnInstall(Object key) {
254            PluginInstaller installer = getPluginInstaller();
255            try {
256                return installer.checkOnInstall(key);
257            } finally {
258                kernel.getProxyManager().destroyProxy(installer);
259            }
260        }
261    
262        public DownloadResults checkOnInstall(Object key, boolean remove) {
263            PluginInstaller installer = getPluginInstaller();
264            try {
265                return installer.checkOnInstall(key, remove);
266            } finally {
267                kernel.getProxyManager().destroyProxy(installer);
268            }
269        }
270    
271        private PluginInstaller getPluginInstaller() {
272            Set<AbstractName> set = kernel.listGBeans(new AbstractNameQuery(PluginInstaller.class.getName()));
273            for (AbstractName name : set) {
274                return (PluginInstaller) kernel.getProxyManager().createProxy(name, PluginInstaller.class);
275            }
276            throw new IllegalStateException("No plugin installer found");
277        }
278        private ServerArchiver getServerArchiver() {
279            Set<AbstractName> set = kernel.listGBeans(new AbstractNameQuery(ServerArchiver.class.getName()));
280            for (AbstractName name : set) {
281                return (ServerArchiver) kernel.getProxyManager().createProxy(name, ServerArchiver.class);
282            }
283            throw new IllegalStateException("No plugin installer found");
284        }
285    
286        //not likely to be useful remotely
287        public PluginListType createPluginListForRepositories(String repo) throws NoSuchStoreException {
288            PluginInstaller installer = getPluginInstaller();
289            try {
290                return installer.createPluginListForRepositories(repo);
291            } finally {
292                kernel.getProxyManager().destroyProxy(installer);
293            }
294        }
295    
296        public Map getInstalledPlugins() {
297            PluginInstaller installer = getPluginInstaller();
298            try {
299                return installer.getInstalledPlugins();
300            } finally {
301                kernel.getProxyManager().destroyProxy(installer);
302            }
303        }
304    
305        public PluginType getPluginMetadata(Artifact configId) {
306            PluginInstaller installer = getPluginInstaller();
307            try {
308                return installer.getPluginMetadata(configId);
309            } finally {
310                kernel.getProxyManager().destroyProxy(installer);
311            }
312        }
313    
314        public void updatePluginMetadata(PluginType metadata) {
315            PluginInstaller installer = getPluginInstaller();
316            try {
317                installer.updatePluginMetadata(metadata);
318            } finally {
319                kernel.getProxyManager().destroyProxy(installer);
320            }
321        }
322    
323        public URL[] getRepositories() {
324            List<URL> list = new ArrayList<URL>();
325            Set<AbstractName> set = kernel.listGBeans(new AbstractNameQuery(PluginRepositoryList.class.getName()));
326            for (AbstractName name : set) {
327                PluginRepositoryList repo = (PluginRepositoryList) kernel.getProxyManager().createProxy(name,
328                        PluginRepositoryList.class);
329                list.addAll(repo.getRepositories());
330                kernel.getProxyManager().destroyProxy(repo);
331            }
332            return list.toArray(new URL[list.size()]);
333        }
334    
335        public Artifact installLibrary(File libFile, String groupId) throws IOException {
336            File[] args = new File[]{libFile};
337            if(!isSameMachine) {
338                AbstractDeployCommand progress = new AbstractDeployCommand(CommandType.DISTRIBUTE, kernel, null, null, null, null, null, false) {
339                    public void run() {
340                    }
341                };
342                progress.addProgressListener(new ProgressListener() {
343                    public void handleProgressEvent(ProgressEvent event) {
344                        log.info(event.getDeploymentStatus().getMessage());
345                    }
346                });
347                progress.setCommandContext(commandContext);
348                RemoteDeployUtil.uploadFilesToServer(args, progress);
349            }
350            Set<AbstractName> set = kernel.listGBeans(new AbstractNameQuery(PluginInstaller.class.getName()));
351            for (AbstractName name : set) {
352                PluginInstaller installer = (PluginInstaller) kernel.getProxyManager().createProxy(name, PluginInstaller.class);
353                // make sure to pass args[0] as RemoteDeployUtil.uploadFilesToServer will update
354                // the args argument with the filenames returned from the server
355                Artifact artifact = installer.installLibrary(args[0], groupId);
356                kernel.getProxyManager().destroyProxy(installer);
357                return artifact;
358            }
359            return null;
360        }
361    
362        public DownloadResults installPluginList(String targetRepositoryPath, String relativeTargetServerPath, PluginListType pluginList) throws Exception {
363            PluginInstaller installer = getPluginInstaller();
364            try {
365                return installer.installPluginList(targetRepositoryPath, relativeTargetServerPath, pluginList);
366            } finally {
367                kernel.getProxyManager().destroyProxy(installer);
368            }
369        }
370    
371        public void mergeOverrides(String server, AttributesType overrides) throws InvalidGBeanException, IOException {
372            PluginInstaller installer = getPluginInstaller();
373            try {
374                installer.mergeOverrides(server, overrides);
375            } finally {
376                kernel.getProxyManager().destroyProxy(installer);
377            }
378        }
379    
380        public File archive(String sourcePath, String destPath, Artifact artifact) throws ArchiverException, IOException {
381            ServerArchiver archiver = getServerArchiver();
382            try {
383                return archiver.archive(sourcePath, destPath, artifact);
384            } finally {
385                kernel.getProxyManager().destroyProxy(archiver);
386            }
387        }
388    
389        public static final GBeanInfo GBEAN_INFO;
390        public static final String GBEAN_REF_MODULE_CONFIGURERS = "ModuleConfigurers";
391    
392        static {
393            GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(RemoteDeploymentManager.class,
394                    "RemoteDeploymentManager");
395            infoFactory.addInterface(GeronimoDeploymentManager.class);
396            infoFactory.addReference(GBEAN_REF_MODULE_CONFIGURERS, ModuleConfigurer.class);
397    
398            infoFactory.setConstructor(new String[]{GBEAN_REF_MODULE_CONFIGURERS});
399    
400            GBEAN_INFO = infoFactory.getBeanInfo();
401        }
402    
403        public static GBeanInfo getGBeanInfo() {
404            return GBEAN_INFO;
405        }
406    
407    }