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    
021    package org.apache.geronimo.system.plugin;
022    
023    import java.io.File;
024    import java.io.FileInputStream;
025    import java.io.FileOutputStream;
026    import java.io.IOException;
027    import java.io.InputStream;
028    import java.io.OutputStream;
029    import java.util.Collection;
030    import java.util.HashMap;
031    import java.util.Map;
032    import java.util.SortedSet;
033    import java.util.LinkedHashSet;
034    import java.util.jar.JarFile;
035    import java.util.zip.ZipEntry;
036    
037    import javax.security.auth.login.FailedLoginException;
038    
039    import org.apache.geronimo.kernel.config.ConfigurationStore;
040    import org.apache.geronimo.kernel.config.NoSuchConfigException;
041    import org.apache.geronimo.kernel.repository.Artifact;
042    import org.apache.geronimo.kernel.repository.FileWriteMonitor;
043    import org.apache.geronimo.kernel.repository.ListableRepository;
044    import org.apache.geronimo.kernel.repository.Repository;
045    import org.apache.geronimo.kernel.repository.WritableListableRepository;
046    import org.apache.geronimo.kernel.repository.WriteableRepository;
047    import org.apache.geronimo.kernel.repository.ArtifactResolver;
048    import org.apache.geronimo.kernel.repository.MissingDependencyException;
049    import org.apache.geronimo.system.configuration.RepositoryConfigurationStore;
050    import org.apache.geronimo.system.plugin.model.PluginListType;
051    import org.apache.geronimo.system.plugin.model.PluginType;
052    
053    /**
054     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
055     */
056    public class GeronimoSourceRepository implements SourceRepository {
057    
058        private final Collection<? extends Repository> repos;
059        private final ArtifactResolver artifactResolver;
060    
061        public GeronimoSourceRepository(Collection<? extends Repository> repos, ArtifactResolver artifactResolver) {
062            this.repos = repos;
063            this.artifactResolver = artifactResolver;
064        }
065    
066        public PluginListType getPluginList() {
067            Map<PluginType, PluginType> pluginMap = new HashMap<PluginType, PluginType>();
068            for (Repository listableRepository : repos) {
069                if (listableRepository instanceof ListableRepository) {
070                    SortedSet<Artifact> artifacts = ((ListableRepository) listableRepository).list();
071                    for (Artifact artifact : artifacts) {
072                        File location = listableRepository.getLocation(artifact);
073                        PluginType data = extractPluginMetadata(location);
074                        if (data != null) {
075                            PluginType key = PluginInstallerGBean.toKey(data);
076                            PluginType existing = pluginMap.get(key);
077                            if (existing == null) {
078                                pluginMap.put(key, data);
079                            } else {
080                                existing.getPluginArtifact().addAll(data.getPluginArtifact());
081                            }
082                        }
083                    }
084                }
085            }
086            PluginListType pluginList = new PluginListType();
087            pluginList.getPlugin().addAll(pluginMap.values());
088            return pluginList;
089        }
090    
091        public OpenResult open(Artifact artifact, FileWriteMonitor monitor) throws IOException, FailedLoginException {
092            try {
093                artifact = artifactResolver.resolveInClassLoader(artifact);
094            } catch (MissingDependencyException e) {
095                return null;
096            }
097            for (Repository repo: repos) {
098                if (repo.contains(artifact)) {
099                    File location = repo.getLocation(artifact);
100                    if (location.isFile()) {
101                        return new LocalOpenResult(artifact, location);
102                    }
103                    if (location.isDirectory()) {
104                        return new ZipOpenResult(artifact, repo);
105                    }
106                }
107            }
108            return null;
109        }
110    
111        PluginType extractPluginMetadata(Artifact artifact) {
112            for (Repository repo: repos) {
113                if (repo.contains(artifact)) {
114                    File location = repo.getLocation(artifact);
115                    return extractPluginMetadata(location);
116                }
117            }
118            return null;
119        }
120    
121        static PluginType extractPluginMetadata(File dir) {
122            try {
123                if (dir.isDirectory()) {
124                    File meta = new File(dir, "META-INF");
125                    if (!meta.isDirectory() || !meta.canRead()) {
126                        return null;
127                    }
128                    File xml = new File(meta, "geronimo-plugin.xml");
129                    if (!xml.isFile() || !xml.canRead() || xml.length() == 0) {
130                            return null;
131                    }
132                    InputStream in = new FileInputStream(xml);
133                    try {
134                        return PluginXmlUtil.loadPluginMetadata(in);
135                    } finally {
136                        in.close();
137                    }
138                } else {
139                    if (!dir.isFile() || !dir.canRead()) {
140                        throw new IllegalStateException("Cannot read configuration " + dir.getAbsolutePath());
141                    }
142                    JarFile jar = new JarFile(dir);
143                    try {
144                        ZipEntry entry = jar.getEntry("META-INF/geronimo-plugin.xml");
145                        if (entry == null) {
146                                return null;
147                        }
148                        InputStream in = jar.getInputStream(entry);
149                        try {
150                            return PluginXmlUtil.loadPluginMetadata(in);
151                        } finally {
152                            in.close();
153                        }
154                    } finally {
155                        jar.close();
156                    }
157                }
158            } catch (Exception e) {
159                //ignore
160            }
161            return null;
162        }
163    
164        private static class RepoWrapper implements WritableListableRepository {
165    
166            private final Repository repo;
167    
168            private RepoWrapper(Repository repo) {
169                this.repo = repo;
170            }
171    
172            public void copyToRepository(File source, Artifact destination, FileWriteMonitor monitor) throws IOException {
173            }
174    
175            public void copyToRepository(InputStream source, int size, Artifact destination, FileWriteMonitor monitor) throws IOException {
176            }
177    
178            public boolean contains(Artifact artifact) {
179                return repo.contains(artifact);
180            }
181    
182            public File getLocation(Artifact artifact) {
183                return repo.getLocation(artifact);
184            }
185    
186            public LinkedHashSet<Artifact> getDependencies(Artifact artifact) {
187                return null;
188            }
189    
190            public SortedSet<Artifact> list() {
191                return null;
192            }
193    
194            public SortedSet<Artifact> list(Artifact query) {
195                return null;
196            }
197        }
198    
199        private class ZipOpenResult implements OpenResult {
200            private final Artifact artifact;
201            private final Repository repo;
202            File location;
203    
204            private ZipOpenResult(Artifact artifact, Repository repo) {
205                this.artifact = artifact;
206                this.repo = repo;
207            }
208    
209            public Artifact getArtifact() {
210                return artifact;
211            }
212    
213            public File getFile() throws IOException {
214                location = File.createTempFile("geronimo-plugin-download-", ".tmp");
215                OutputStream output = new FileOutputStream(location);
216                WritableListableRepository writableRepo = new RepoWrapper(repo);
217                ConfigurationStore store = new RepositoryConfigurationStore(writableRepo);
218                try {
219                    store.exportConfiguration(artifact, output);
220                } catch (NoSuchConfigException e) {
221                    throw (IOException)new IOException("Could not locate artefact " + artifact).initCause(e);
222                }
223    
224                return location;
225            }
226    
227            public void install(WriteableRepository repo, FileWriteMonitor monitor) throws IOException {
228                File file = getFile();
229                repo.copyToRepository(file, artifact, monitor);
230                if (!file.delete()) {
231    //                log.warn("Unable to delete temporary download file " + tempFile.getAbsolutePath());
232                    file.deleteOnExit();
233                }
234            }
235    
236            public void close() {
237            }
238        }
239    }