View Javadoc

1   /**
2    *
3    *  Licensed to the Apache Software Foundation (ASF) under one or more
4    *  contributor license agreements.  See the NOTICE file distributed with
5    *  this work for additional information regarding copyright ownership.
6    *  The ASF licenses this file to You under the Apache License, Version 2.0
7    *  (the "License"); you may not use this file except in compliance with
8    *  the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing, software
13   *  distributed under the License is distributed on an "AS IS" BASIS,
14   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   *  See the License for the specific language governing permissions and
16   *  limitations under the License.
17   */
18  package org.apache.geronimo.system.repository;
19  
20  import java.io.File;
21  import java.io.FileInputStream;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.net.MalformedURLException;
25  import java.net.URI;
26  import java.net.URISyntaxException;
27  import java.net.URL;
28  import java.net.URLClassLoader;
29  import java.util.Enumeration;
30  import java.util.LinkedHashSet;
31  import java.util.Map;
32  import java.util.HashMap;
33  import java.util.zip.ZipEntry;
34  import java.util.zip.ZipException;
35  import java.util.zip.ZipFile;
36  import javax.xml.parsers.DocumentBuilderFactory;
37  import javax.xml.parsers.ParserConfigurationException;
38  
39  import org.apache.commons.logging.Log;
40  import org.apache.commons.logging.LogFactory;
41  import org.apache.geronimo.kernel.repository.Artifact;
42  import org.apache.geronimo.kernel.repository.ArtifactTypeHandler;
43  import org.apache.geronimo.kernel.repository.FileWriteMonitor;
44  import org.apache.geronimo.kernel.repository.WriteableRepository;
45  import org.apache.geronimo.kernel.util.XmlUtil;
46  import org.apache.geronimo.system.serverinfo.ServerInfo;
47  import org.w3c.dom.Document;
48  import org.w3c.dom.Element;
49  import org.w3c.dom.Node;
50  import org.w3c.dom.NodeList;
51  import org.xml.sax.InputSource;
52  import org.xml.sax.SAXException;
53  
54  /**
55   * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
56   */
57  public abstract class AbstractRepository implements WriteableRepository {
58      protected static final Log log = LogFactory.getLog(AbstractRepository.class);
59      private final static ArtifactTypeHandler DEFAULT_TYPE_HANDLER = new CopyArtifactTypeHandler();
60      protected final File rootFile;
61      private final Map typeHandlers = new HashMap();
62  
63      public AbstractRepository(URI root, ServerInfo serverInfo) {
64          this(resolveRoot(root, serverInfo));
65      }
66  
67      public AbstractRepository(File rootFile) {
68          if (rootFile == null) throw new NullPointerException("root is null");
69  
70          if (!rootFile.exists() || !rootFile.isDirectory() || !rootFile.canRead()) {
71              throw new IllegalStateException("Maven2Repository must have a root that's a valid readable directory (not " + rootFile.getAbsolutePath() + ")");
72          }
73  
74          this.rootFile = rootFile;
75          log.debug("Repository root is " + rootFile.getAbsolutePath());
76  
77          typeHandlers.put("car", new UnpackArtifactTypeHandler());
78      }
79  
80      private static File resolveRoot(URI root, ServerInfo serverInfo) {
81          if (root == null) throw new NullPointerException("root is null");
82  
83          if (!root.toString().endsWith("/")) {
84              try {
85                  root = new URI(root.toString() + "/");
86              } catch (URISyntaxException e) {
87                  throw new RuntimeException("Invalid repository root (does not end with / ) and can't add myself", e);
88              }
89          }
90  
91          URI resolvedUri;
92          if (serverInfo != null) {
93              resolvedUri = serverInfo.resolve(root);
94          } else {
95              resolvedUri = root;
96          }
97  
98          if (!resolvedUri.getScheme().equals("file")) {
99              throw new IllegalStateException("FileSystemRepository must have a root that's a local directory (not " + resolvedUri + ")");
100         }
101 
102         File rootFile = new File(resolvedUri);
103         return rootFile;
104     }
105 
106     public boolean contains(Artifact artifact) {
107         // Note: getLocation(artifact) does an artifact.isResolved() check - no need to do it here.
108         File location = getLocation(artifact);
109         return location.canRead() && (location.isFile() || new File(location, "META-INF").isDirectory());
110     }
111 
112     private static final String NAMESPACE = "http://geronimo.apache.org/xml/ns/deployment-1.2";
113     public LinkedHashSet getDependencies(Artifact artifact) {
114         if(!artifact.isResolved()) {
115             throw new IllegalArgumentException("Artifact "+artifact+" is not fully resolved");
116         }
117         LinkedHashSet dependencies = new LinkedHashSet();
118         URL url;
119         try {
120             File location = getLocation(artifact);
121             url = location.toURL();
122         } catch (MalformedURLException e) {
123             throw (IllegalStateException)new IllegalStateException("Unable to get URL for dependency " + artifact).initCause(e);
124         }
125         ClassLoader depCL = new URLClassLoader(new URL[]{url}, ClassLoader.getSystemClassLoader());
126         InputStream is = depCL.getResourceAsStream("META-INF/geronimo-dependency.xml");
127         try {
128             if (is != null) {
129                 InputSource in = new InputSource(is);
130                 DocumentBuilderFactory dfactory = XmlUtil.newDocumentBuilderFactory();
131                 dfactory.setNamespaceAware(true);
132                 try {
133                     Document doc = dfactory.newDocumentBuilder().parse(in);
134                     Element root = doc.getDocumentElement();
135                     NodeList configs = root.getElementsByTagNameNS(NAMESPACE, "dependency");
136                     for (int i = 0; i < configs.getLength(); i++) {
137                         Element dependencyElement = (Element) configs.item(i);
138                         String groupId = getString(dependencyElement, "groupId");
139                         String artifactId = getString(dependencyElement, "artifactId");
140                         String version = getString(dependencyElement, "version");
141                         String type = getString(dependencyElement, "type");
142                         if (type == null) {
143                             type = "jar";
144                         }
145                         dependencies.add(new Artifact(groupId, artifactId,  version, type));
146                     }
147                 } catch (IOException e) {
148                     throw (IllegalStateException)new IllegalStateException("Unable to parse geronimo-dependency.xml file in " + url).initCause(e);
149                 } catch (ParserConfigurationException e) {
150                     throw (IllegalStateException)new IllegalStateException("Unable to parse geronimo-dependency.xml file in " + url).initCause(e);
151                 } catch (SAXException e) {
152                     throw (IllegalStateException)new IllegalStateException("Unable to parse geronimo-dependency.xml file in " + url).initCause(e);
153                 }
154             }
155         } finally {
156             if (is != null) {
157                 try {
158                     is.close();
159                 } catch (IOException ignore) {
160                     // ignore
161                 }
162             }
163         }
164         return dependencies;
165     }
166 
167     private String getString(Element dependencyElement, String childName) {
168         NodeList children = dependencyElement.getElementsByTagNameNS(NAMESPACE, childName);
169         if (children == null || children.getLength() == 0) {
170         return null;
171         }
172         String value = "";
173         NodeList text = children.item(0).getChildNodes();
174         for (int t = 0; t < text.getLength(); t++) {
175             Node n = text.item(t);
176             if (n.getNodeType() == Node.TEXT_NODE) {
177                 value += n.getNodeValue();
178             }
179         }
180         return value.trim();
181     }
182 
183     public void setTypeHandler(String type, ArtifactTypeHandler handler) {
184         typeHandlers.put(type, handler);
185     }
186 
187     public void copyToRepository(File source, Artifact destination, FileWriteMonitor monitor) throws IOException {
188         if(!destination.isResolved()) {
189             throw new IllegalArgumentException("Artifact "+destination+" is not fully resolved");
190         }
191         if (!source.exists() || !source.canRead() || source.isDirectory()) {
192             throw new IllegalArgumentException("Cannot read source file at " + source.getAbsolutePath());
193         }
194         int size = 0;
195         try {
196             ZipFile zip = new ZipFile(source);
197             for (Enumeration entries=zip.entries(); entries.hasMoreElements();) {
198             	ZipEntry entry = (ZipEntry)entries.nextElement();
199             	size += entry.getSize();
200             }
201         } catch (ZipException ze) {
202         	size = (int)source.length();
203         }
204         FileInputStream is = new FileInputStream(source);
205         try {
206             copyToRepository(is, size, destination, monitor);
207         } finally {
208             try {
209                 is.close();
210             } catch (IOException ignored) {
211                 // ignored
212             }
213         }
214     }
215 
216     public void copyToRepository(InputStream source, int size, Artifact destination, FileWriteMonitor monitor) throws IOException {
217         if(!destination.isResolved()) {
218             throw new IllegalArgumentException("Artifact "+destination+" is not fully resolved");
219         }
220         // is this a writable repository
221         if (!rootFile.canWrite()) {
222             throw new IllegalStateException("This repository is not writable: " + rootFile.getAbsolutePath() + ")");
223         }
224 
225         // where are we going to install the file
226         File location = getLocation(destination);
227 
228         // assure that there isn't already a file installed at the specified location
229         if (location.exists()) {
230             throw new IllegalArgumentException("Destination " + location.getAbsolutePath() + " already exists!");
231         }
232 
233         ArtifactTypeHandler typeHandler = (ArtifactTypeHandler) typeHandlers.get(destination.getType());
234         if (typeHandler == null) typeHandler = DEFAULT_TYPE_HANDLER;
235         typeHandler.install(source, size, destination, monitor, location);
236         
237         if (destination.getType().equalsIgnoreCase("car")) {
238             log.debug("Installed module configuration; id=" + destination + "; location=" + location);
239         }
240     }
241 }