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
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
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
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
221 if (!rootFile.canWrite()) {
222 throw new IllegalStateException("This repository is not writable: " + rootFile.getAbsolutePath() + ")");
223 }
224
225
226 File location = getLocation(destination);
227
228
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 }