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.kernel.repository;
018
019 import java.io.File;
020 import java.io.FileInputStream;
021 import java.io.IOException;
022 import java.io.InputStream;
023 import java.net.MalformedURLException;
024 import java.net.URL;
025 import java.net.URLClassLoader;
026 import java.util.Enumeration;
027 import java.util.HashMap;
028 import java.util.LinkedHashSet;
029 import java.util.Map;
030 import java.util.zip.ZipEntry;
031 import java.util.zip.ZipException;
032 import java.util.zip.ZipFile;
033
034 import javax.xml.parsers.DocumentBuilderFactory;
035 import javax.xml.parsers.ParserConfigurationException;
036
037 import org.apache.commons.logging.Log;
038 import org.apache.commons.logging.LogFactory;
039 import org.apache.geronimo.kernel.util.XmlUtil;
040 import org.w3c.dom.Document;
041 import org.w3c.dom.Element;
042 import org.w3c.dom.Node;
043 import org.w3c.dom.NodeList;
044 import org.xml.sax.InputSource;
045 import org.xml.sax.SAXException;
046
047 /**
048 * @version $Rev: 506425 $ $Date: 2007-02-12 22:49:46 +1100 (Mon, 12 Feb 2007) $
049 */
050 public abstract class AbstractRepository implements WriteableRepository {
051 protected static final Log log = LogFactory.getLog(AbstractRepository.class);
052 private final static ArtifactTypeHandler DEFAULT_TYPE_HANDLER = new CopyArtifactTypeHandler();
053 protected final File rootFile;
054 private final Map typeHandlers = new HashMap();
055
056 public AbstractRepository(File rootFile) {
057 if (rootFile == null) throw new NullPointerException("root is null");
058
059 if (!rootFile.exists() || !rootFile.isDirectory() || !rootFile.canRead()) {
060 throw new IllegalStateException("Maven2Repository must have a root that's a valid readable directory (not " + rootFile.getAbsolutePath() + ")");
061 }
062
063 this.rootFile = rootFile;
064 log.debug("Repository root is " + rootFile.getAbsolutePath());
065
066 typeHandlers.put("car", new UnpackArtifactTypeHandler());
067 }
068
069 public boolean contains(Artifact artifact) {
070 // Note: getLocation(artifact) does an artifact.isResolved() check - no need to do it here.
071 File location = getLocation(artifact);
072 return location.canRead() && (location.isFile() || new File(location, "META-INF").isDirectory());
073 }
074
075 private static final String NAMESPACE = "http://geronimo.apache.org/xml/ns/deployment-1.2";
076 public LinkedHashSet getDependencies(Artifact artifact) {
077 if(!artifact.isResolved()) {
078 throw new IllegalArgumentException("Artifact "+artifact+" is not fully resolved");
079 }
080 LinkedHashSet dependencies = new LinkedHashSet();
081 URL url;
082 try {
083 File location = getLocation(artifact);
084 url = location.toURL();
085 } catch (MalformedURLException e) {
086 throw (IllegalStateException)new IllegalStateException("Unable to get URL for dependency " + artifact).initCause(e);
087 }
088 ClassLoader depCL = new URLClassLoader(new URL[]{url}, new ClassLoader() {
089 @Override
090 public URL getResource(String name) {
091 return null;
092 }
093 });
094 InputStream is = depCL.getResourceAsStream("META-INF/geronimo-dependency.xml");
095 try {
096 if (is != null) {
097 InputSource in = new InputSource(is);
098 DocumentBuilderFactory dfactory = XmlUtil.newDocumentBuilderFactory();
099 dfactory.setNamespaceAware(true);
100 try {
101 Document doc = dfactory.newDocumentBuilder().parse(in);
102 Element root = doc.getDocumentElement();
103 NodeList configs = root.getElementsByTagNameNS(NAMESPACE, "dependency");
104 for (int i = 0; i < configs.getLength(); i++) {
105 Element dependencyElement = (Element) configs.item(i);
106 String groupId = getString(dependencyElement, "groupId");
107 String artifactId = getString(dependencyElement, "artifactId");
108 String version = getString(dependencyElement, "version");
109 String type = getString(dependencyElement, "type");
110 if (type == null) {
111 type = "jar";
112 }
113 dependencies.add(new Artifact(groupId, artifactId, version, type));
114 }
115 } catch (IOException e) {
116 throw (IllegalStateException)new IllegalStateException("Unable to parse geronimo-dependency.xml file in " + url).initCause(e);
117 } catch (ParserConfigurationException e) {
118 throw (IllegalStateException)new IllegalStateException("Unable to parse geronimo-dependency.xml file in " + url).initCause(e);
119 } catch (SAXException e) {
120 throw (IllegalStateException)new IllegalStateException("Unable to parse geronimo-dependency.xml file in " + url).initCause(e);
121 }
122 }
123 } finally {
124 if (is != null) {
125 try {
126 is.close();
127 } catch (IOException ignore) {
128 // ignore
129 }
130 }
131 }
132 return dependencies;
133 }
134
135 private String getString(Element dependencyElement, String childName) {
136 NodeList children = dependencyElement.getElementsByTagNameNS(NAMESPACE, childName);
137 if (children == null || children.getLength() == 0) {
138 return null;
139 }
140 String value = "";
141 NodeList text = children.item(0).getChildNodes();
142 for (int t = 0; t < text.getLength(); t++) {
143 Node n = text.item(t);
144 if (n.getNodeType() == Node.TEXT_NODE) {
145 value += n.getNodeValue();
146 }
147 }
148 return value.trim();
149 }
150
151 public void setTypeHandler(String type, ArtifactTypeHandler handler) {
152 typeHandlers.put(type, handler);
153 }
154
155 public void copyToRepository(File source, Artifact destination, FileWriteMonitor monitor) throws IOException {
156 if(!destination.isResolved()) {
157 throw new IllegalArgumentException("Artifact "+destination+" is not fully resolved");
158 }
159 if (!source.exists() || !source.canRead() || source.isDirectory()) {
160 throw new IllegalArgumentException("Cannot read source file at " + source.getAbsolutePath());
161 }
162 int size = 0;
163 try {
164 ZipFile zip = new ZipFile(source);
165 for (Enumeration entries=zip.entries(); entries.hasMoreElements();) {
166 ZipEntry entry = (ZipEntry)entries.nextElement();
167 size += entry.getSize();
168 }
169 } catch (ZipException ze) {
170 size = (int)source.length();
171 }
172 FileInputStream is = new FileInputStream(source);
173 try {
174 copyToRepository(is, size, destination, monitor);
175 } finally {
176 try {
177 is.close();
178 } catch (IOException ignored) {
179 // ignored
180 }
181 }
182 }
183
184 public void copyToRepository(InputStream source, int size, Artifact destination, FileWriteMonitor monitor) throws IOException {
185 if(!destination.isResolved()) {
186 throw new IllegalArgumentException("Artifact "+destination+" is not fully resolved");
187 }
188 // is this a writable repository
189 if (!rootFile.canWrite()) {
190 throw new IllegalStateException("This repository is not writable: " + rootFile.getAbsolutePath() + ")");
191 }
192
193 // where are we going to install the file
194 File location = getLocation(destination);
195
196 // assure that there isn't already a file installed at the specified location
197 if (location.exists()) {
198 throw new IllegalArgumentException("Destination " + location.getAbsolutePath() + " already exists!");
199 }
200
201 ArtifactTypeHandler typeHandler = (ArtifactTypeHandler) typeHandlers.get(destination.getType());
202 if (typeHandler == null) typeHandler = DEFAULT_TYPE_HANDLER;
203 typeHandler.install(source, size, destination, monitor, location);
204
205 if (destination.getType().equalsIgnoreCase("car")) {
206 log.debug("Installed module configuration; id=" + destination + "; location=" + location);
207 }
208 }
209 }