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.cli;
018    
019    import java.io.IOException;
020    import java.net.URL;
021    import java.util.ArrayList;
022    import java.util.Collection;
023    import java.util.Comparator;
024    import java.util.List;
025    import java.util.Map;
026    import java.util.TreeMap;
027    import java.util.TreeSet;
028    
029    import javax.enterprise.deploy.spi.DeploymentManager;
030    import javax.security.auth.login.FailedLoginException;
031    
032    import jline.ConsoleReader;
033    import org.apache.geronimo.cli.deployer.CommandArgs;
034    import org.apache.geronimo.common.DeploymentException;
035    import org.apache.geronimo.deployment.plugin.GeronimoDeploymentManager;
036    import org.apache.geronimo.kernel.config.NoSuchStoreException;
037    import org.apache.geronimo.system.plugin.DownloadResults;
038    import org.apache.geronimo.system.plugin.PluginInstallerGBean;
039    import org.apache.geronimo.system.plugin.model.PluginArtifactType;
040    import org.apache.geronimo.system.plugin.model.PluginListType;
041    import org.apache.geronimo.system.plugin.model.PluginType;
042    
043    /**
044     * The CLI deployer logic to start.
045     *
046     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
047     */
048    public class CommandListConfigurations extends AbstractCommand {
049    
050        //todo: provide a way to handle a username and password for the remote repo?
051    
052        public void execute(ConsoleReader consoleReader, ServerConnection connection, CommandArgs commandArgs) throws DeploymentException {
053            DeploymentManager dmgr = connection.getDeploymentManager();
054            if (dmgr instanceof GeronimoDeploymentManager) {
055                GeronimoDeploymentManager mgr = (GeronimoDeploymentManager) dmgr;
056                try {
057                    String repo;
058                    if (commandArgs.getArgs().length == 1) {
059                        repo = commandArgs.getArgs()[0];
060                    } else {
061                        repo = getRepository(consoleReader, mgr);
062                    }
063                    PluginListType plugins = getPluginCategories(repo, mgr, consoleReader);
064                    if (plugins == null) {
065                        return;
066                    }
067    
068                    PluginListType list = getInstallList(plugins, consoleReader, repo);
069                    if (list == null) {
070                        return;
071                    }
072    
073                    installPlugins(mgr, list, repo, consoleReader, connection);
074                } catch (IOException e) {
075                    throw new DeploymentException("Unable to install configuration", e);
076                } catch (NumberFormatException e) {
077                    throw new DeploymentException("Invalid response");
078                }
079            } else {
080                throw new DeploymentException("Cannot list repositories using " + dmgr.getClass().getName() + " deployment manager");
081            }
082        }
083    
084        public String getRepository(ConsoleReader consoleReader, GeronimoDeploymentManager mgr) throws IOException, DeploymentException {
085            URL[] all = mgr.getRepositories();
086            if (all.length == 0) {
087                throw new DeploymentException("No default repositories available.  Please either specify the repository " +
088                        "URL on the command line, or go into the console Plugin page and update the list of available " +
089                        "repositories.");
090            }
091            // no need to ask for input if only one repo exists
092            if (all.length == 1) {
093                String repo = all[0].toString();
094                consoleReader.printNewline();
095                consoleReader.printString("Selected repository: " + repo);
096                consoleReader.printNewline();
097                return repo;
098            }
099    
100            consoleReader.printNewline();
101            consoleReader.printString("Select repository:");
102            consoleReader.printNewline();
103            for (int i = 0; i < all.length; i++) {
104                URL url = all[i];
105                DeployUtils.printTo("  " + (i + 1) + ". ", 8, consoleReader);
106                DeployUtils.println(url.toString(), 0, consoleReader);
107            }
108            String entry = consoleReader.readLine("Enter Repository Number: ").trim();
109            if (entry.length() == 0) {
110                return null;
111            }
112            try {
113                int index = Integer.parseInt(entry);
114                return all[index - 1].toString();
115            } catch (NumberFormatException e) {
116                throw new DeploymentException("Invalid selection");
117            } catch (ArrayIndexOutOfBoundsException e) {
118                throw new DeploymentException("Invalid selection");
119            }
120        }
121    
122        public PluginListType getPluginCategories(String repo, GeronimoDeploymentManager mgr, ConsoleReader consoleReader) throws DeploymentException, IOException {
123            if (repo == null) {
124                return null;
125            }
126            PluginListType data;
127            URL repository;
128            try {
129                repository = new URL(repo);
130                data = mgr.listPlugins(repository, null, null);
131            } catch (IOException e) {
132                throw new DeploymentException("Unable to list configurations", e);
133            } catch (FailedLoginException e) {
134                throw new DeploymentException("Invalid login for Maven repository '" + repo + "'", e);
135            }
136            if (data == null || data.getPlugin().size() == 0) {
137                return null;
138            }
139            return data;
140        }
141    
142        public PluginListType getLocalPluginCategories(GeronimoDeploymentManager mgr, ConsoleReader consoleReader) throws DeploymentException, IOException {
143            PluginListType data;
144            try {
145                data = mgr.createPluginListForRepositories(null);
146            } catch (NoSuchStoreException e) {
147                throw new DeploymentException("Unable to list configurations", e);
148            }
149            if (data == null || data.getPlugin().size() == 0) {
150                return null;
151            }
152            return data;
153        }
154    
155        private Map<String, Collection<PluginType>> writePluginList(PluginListType data, ConsoleReader consoleReader) throws IOException {
156            if (data == null) {
157                consoleReader.printNewline();
158                consoleReader.printString("No plugins were returned from this site.");
159                consoleReader.printNewline();
160                consoleReader.flushConsole();
161                return null;
162            }
163            Map<String, Collection<PluginType>> categories = new TreeMap<String, Collection<PluginType>>();
164            Comparator<PluginType> comp = new Comparator<PluginType>() {
165    
166                public int compare(PluginType o1, PluginType o2) {
167                    return o1.getName().compareTo(o2.getName());
168                }
169            };
170            for (PluginType metadata : data.getPlugin()) {
171                String category = metadata.getCategory();
172                if (category == null) {
173                    category = "<no category>";
174                }
175                Collection<PluginType> list = categories.get(category);
176                if (list == null) {
177                    list = new TreeSet<PluginType>(comp);
178                    categories.put(category, list);
179                }
180                list.add(metadata);
181            }
182            return categories;
183        }
184    
185        public PluginListType getInstallList(PluginListType plugins, ConsoleReader consoleReader, String repo) throws IOException {
186            Map<String, Collection<PluginType>> categories = writePluginList(plugins, consoleReader);
187            if (categories == null) {
188                return null;
189            }
190            List<PluginType> available = new ArrayList<PluginType>();
191            for (Map.Entry<String, Collection<PluginType>> entry : categories.entrySet()) {
192                String category = entry.getKey();
193                Collection<PluginType> items = entry.getValue();
194                consoleReader.printString(category);
195                consoleReader.printNewline();
196                for (PluginType metadata : items) {
197                    for (PluginArtifactType instance : metadata.getPluginArtifact()) {
198                        PluginType copy = PluginInstallerGBean.copy(metadata, instance);
199                        available.add(copy);
200                        DeployUtils.printTo("  " + available.size() + ":  ", 10, consoleReader);
201                        DeployUtils.println(metadata.getName() + " (" + instance.getModuleId().getVersion() + ")", 0, consoleReader);
202                    }
203                }
204            }
205            if (available.size() == 0) {
206                consoleReader.printNewline();
207                consoleReader.printString("No plugins from this site are eligible for installation.");
208                consoleReader.printNewline();
209                return null;
210            }
211            consoleReader.printNewline();
212            consoleReader.flushConsole();
213            String answer = consoleReader.readLine("Install Services [enter a comma separated list of numbers or 'q' to quit]: ").trim();
214            if (answer.equalsIgnoreCase("q")) {
215                return null;
216            }
217            PluginListType list = new PluginListType();
218            for (String instance : answer.split(",")) {
219                int selection = Integer.parseInt(instance.trim());
220                PluginType target = available.get(selection - 1);
221                list.getPlugin().add(target);
222            }
223            if (repo != null) {
224                list.getDefaultRepository().add(repo);
225            }
226            return list;
227        }
228    
229        public void installPlugins(GeronimoDeploymentManager mgr, PluginListType list, String defaultRepository, ConsoleReader consoleReader, ServerConnection connection) throws IOException, DeploymentException {
230            long start = System.currentTimeMillis();
231            Object key = mgr.startInstall(list, defaultRepository, false, null, null);
232            DownloadResults results = CommandInstallCAR.showProgress(consoleReader, mgr, key);
233            int time = (int) (System.currentTimeMillis() - start) / 1000;
234            CommandInstallCAR.printResults(consoleReader, results, time);
235        }
236    
237        public void installPlugins(GeronimoDeploymentManager mgr, List<String> list, PluginListType all, String defaultRepository, ConsoleReader consoleReader, ServerConnection connection) throws IOException, DeploymentException {
238            PluginListType selected = getPluginsFromIds(list, all);
239            installPlugins(mgr, selected, defaultRepository, consoleReader, connection);
240        }
241    
242        private static PluginListType getPluginsFromIds(List<String> configIds, PluginListType list) throws IllegalStateException {
243            PluginListType installList = new PluginListType();
244            for (String configId : configIds) {
245                PluginType plugin = null;
246                for (PluginType metadata : list.getPlugin()) {
247                    for (PluginArtifactType testInstance : metadata.getPluginArtifact()) {
248                        if (PluginInstallerGBean.toArtifact(testInstance.getModuleId()).toString().equals(configId)) {
249                            plugin = PluginInstallerGBean.copy(metadata, testInstance);
250                            installList.getPlugin().add(plugin);
251                            break;
252                        }
253                    }
254                }
255                if (plugin == null) {
256                    throw new IllegalStateException("No configuration found for '" + configId + "'");
257                }
258            }
259            return installList;
260        }
261    
262    
263        public void assembleServer(GeronimoDeploymentManager mgr, PluginListType list, String repositoryPath, String relativeServerPath, ConsoleReader consoleReader) throws Exception {
264            long start = System.currentTimeMillis();
265            DownloadResults results = mgr.installPluginList(repositoryPath, relativeServerPath, list);
266            int time = (int) (System.currentTimeMillis() - start) / 1000;
267            CommandInstallCAR.printResults(consoleReader, results, time);
268        }
269        public void assembleServer(GeronimoDeploymentManager mgr, List<String> list, PluginListType all, String repositoryPath, String relativeServerPath, ConsoleReader consoleReader) throws Exception {
270            PluginListType selected = getPluginsFromIds(list, all);
271            assembleServer(mgr, selected, repositoryPath, relativeServerPath, consoleReader);
272        }
273    
274    }