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: */package org.apache.geronimo.console.car;
017:
018: import java.io.BufferedInputStream;
019: import java.io.File;
020: import java.io.FileInputStream;
021: import java.io.IOException;
022: import java.io.InputStream;
023: import java.io.OutputStream;
024: import java.io.PrintWriter;
025: import java.util.Iterator;
026: import java.util.Set;
027:
028: import javax.servlet.ServletException;
029: import javax.servlet.http.HttpServlet;
030: import javax.servlet.http.HttpServletRequest;
031: import javax.servlet.http.HttpServletResponse;
032: import javax.xml.bind.JAXBException;
033: import javax.xml.parsers.DocumentBuilder;
034: import javax.xml.parsers.DocumentBuilderFactory;
035: import javax.xml.parsers.ParserConfigurationException;
036: import javax.xml.stream.XMLStreamException;
037: import javax.xml.transform.OutputKeys;
038: import javax.xml.transform.Transformer;
039: import javax.xml.transform.TransformerException;
040: import javax.xml.transform.TransformerFactory;
041: import javax.xml.transform.dom.DOMSource;
042: import javax.xml.transform.stream.StreamResult;
043:
044: import org.apache.commons.logging.Log;
045: import org.apache.commons.logging.LogFactory;
046: import org.apache.geronimo.gbean.AbstractName;
047: import org.apache.geronimo.gbean.AbstractNameQuery;
048: import org.apache.geronimo.kernel.Kernel;
049: import org.apache.geronimo.kernel.KernelRegistry;
050: import org.apache.geronimo.kernel.config.ConfigurationManager;
051: import org.apache.geronimo.kernel.config.ConfigurationStore;
052: import org.apache.geronimo.kernel.config.ConfigurationUtil;
053: import org.apache.geronimo.kernel.config.NoSuchConfigException;
054: import org.apache.geronimo.kernel.config.NoSuchStoreException;
055: import org.apache.geronimo.kernel.repository.Artifact;
056: import org.apache.geronimo.kernel.repository.Repository;
057: import org.apache.geronimo.kernel.repository.Version;
058: import org.apache.geronimo.kernel.util.XmlUtil;
059: import org.apache.geronimo.system.plugin.PluginInstaller;
060: import org.apache.geronimo.system.plugin.PluginXmlUtil;
061: import org.apache.geronimo.system.plugin.model.PluginListType;
062: import org.w3c.dom.Document;
063: import org.w3c.dom.Element;
064: import org.w3c.dom.Text;
065:
066: /**
067: * Servlet that lets you download a CAR from the repository
068: *
069: * @version $Rev: 601152 $ $Date: 2007-12-04 15:49:03 -0800 (Tue, 04 Dec 2007) $
070: */
071: public class GeronimoAsMavenServlet extends HttpServlet {
072: private final static Log log = LogFactory
073: .getLog(GeronimoAsMavenServlet.class);
074:
075: protected void doHead(HttpServletRequest httpServletRequest,
076: HttpServletResponse httpServletResponse)
077: throws ServletException, IOException {
078: handleRequest(httpServletRequest, httpServletResponse, false);
079: }
080:
081: protected void doGet(HttpServletRequest request,
082: HttpServletResponse response) throws ServletException,
083: IOException {
084: handleRequest(request, response, true);
085: }
086:
087: protected void handleRequest(HttpServletRequest request,
088: HttpServletResponse response, boolean reply)
089: throws ServletException, IOException {
090: String path = request.getPathInfo();
091: if (path == null) {
092: throw new ServletException(
093: "No configId specified for CAR download");
094: }
095: Kernel kernel = KernelRegistry.getSingleKernel();
096: if (path.equals("/geronimo-plugins.xml")) {
097: response.setContentType("text/xml");
098: if (reply) {
099: try {
100: generateConfigFile(request, kernel, response
101: .getWriter());
102: } catch (Exception e) {
103: throw new ServletException(
104: "Unable to generate Geronimo configuration list",
105: e);
106: }
107: }
108: } else if (path.endsWith("/maven-metadata.xml")) {
109: response.setContentType("text/xml");
110: try {
111: String start = path.substring(0, path.lastIndexOf('/'));
112: if (start.charAt(0) == '/') {
113: start = start.substring(1);
114: }
115: String[] parts = start.split("/");
116: if (parts.length > 2) {
117: StringBuffer buf = new StringBuffer();
118: for (int i = 0; i < parts.length - 1; i++) {
119: String part = parts[i];
120: if (i > 0)
121: buf.append('.');
122: buf.append(part);
123: }
124: generateMavenFile(kernel, response.getWriter(), buf
125: .toString(), parts[parts.length - 1], reply);
126: } else {
127: generateMavenFile(kernel, response.getWriter(),
128: parts[0], parts[1], reply);
129: }
130: } catch (Exception e) {
131: throw new ServletException(
132: "Unable to generate Geronimo configuration list",
133: e);
134: }
135: } else {
136: if (path.startsWith("/")) {
137: path = path.substring(1);
138: }
139: String configId = parsePath(path, response);
140: if (configId == null) { // we already sent the 404
141: return;
142: }
143: if (!produceDownloadFile(kernel, Artifact.create(configId),
144: response, reply)) {
145: response.sendError(404, "Cannot locate download file "
146: + path);
147: }
148: }
149: }
150:
151: private static String parsePath(String path,
152: HttpServletResponse response) throws IOException {
153: String[] parts = path.split("/");
154: String groupId, artifactId, version, type;
155: if (parts.length < 4) {
156: response.sendError(404, "Unrecognized path form " + path);
157: return null;
158: } else { // e.g. console/MyDatabase/1.0-SNAPSHOT/MyDatabase-1.0-SNAPSHOT.rar
159: groupId = parts[0];
160: for (int i = 4; i < parts.length; i++) {
161: groupId = groupId + "." + parts[i - 3];
162: }
163: artifactId = parts[parts.length - 3];
164: version = parts[parts.length - 2];
165: if (!parts[parts.length - 1].startsWith(artifactId + "-"
166: + version)) {
167: response.sendError(404, "Unrecognized path structure "
168: + path);
169: return null;
170: }
171: type = parts[parts.length - 1].substring(artifactId
172: .length()
173: + version.length() + 2);
174: }
175: return groupId + "/" + artifactId + "/" + version + "/" + type;
176: }
177:
178: private boolean produceDownloadFile(Kernel kernel,
179: Artifact configId, HttpServletResponse response,
180: boolean reply) throws IOException {
181: //todo: replace kernel mumbo jumbo with JSR-77 navigation
182: // Step 1: check if it's in a configuration store
183: ConfigurationManager mgr = ConfigurationUtil
184: .getConfigurationManager(kernel);
185: if (mgr.isConfiguration(configId)) {
186: ConfigurationStore store = mgr
187: .getStoreForConfiguration(configId);
188: response.setContentType("application/zip");
189: if (!reply) {
190: return true;
191: }
192: try {
193: store.exportConfiguration(configId, response
194: .getOutputStream());
195: return true;
196: } catch (NoSuchConfigException e) {
197: log
198: .error(
199: "Inconsistent ConfigurationStore data; ConfigManager claims it has configuration "
200: + configId
201: + " but store claims it doesn't",
202: e);
203: throw new IOException(
204: "Unable to write ZIP file; see server log for details");
205: }
206: }
207: // Step 2: check if it's in a repository
208: Set repos = kernel.listGBeans(new AbstractNameQuery(
209: Repository.class.getName()));
210: for (Iterator it = repos.iterator(); it.hasNext();) {
211: AbstractName name = (AbstractName) it.next();
212: Repository repo = (Repository) kernel.getProxyManager()
213: .createProxy(name, Repository.class);
214: if (repo.contains(configId)) {
215: File path = repo.getLocation(configId);
216: if (!path.exists())
217: throw new IllegalStateException(
218: "Can't find file '"
219: + path.getAbsolutePath()
220: + "' though repository said there's an artifact there!");
221: response.setContentType("application/zip");
222: if (!reply) {
223: return true;
224: }
225: InputStream in = new BufferedInputStream(
226: new FileInputStream(path));
227: response.setContentLength((int) path.length());
228: OutputStream out = response.getOutputStream();
229: byte[] buf = new byte[1024];
230: int count;
231: while ((count = in.read(buf)) > -1) {
232: out.write(buf, 0, count);
233: }
234: in.close();
235: return true;
236: }
237: }
238: // Step 3: wasn't found
239: return false;
240: }
241:
242: private void generateConfigFile(HttpServletRequest request,
243: Kernel kernel, PrintWriter out)
244: throws NoSuchStoreException, JAXBException,
245: XMLStreamException {
246: String repo = request.getScheme() + "://"
247: + request.getServerName() + ":"
248: + request.getServerPort() + request.getContextPath()
249: + request.getServletPath();
250: if (!repo.endsWith("/"))
251: repo += "/";
252: ConfigurationManager mgr = ConfigurationUtil
253: .getConfigurationManager(kernel);
254: PluginInstaller installer = getInstaller(kernel);
255: PluginListType pluginList = installer
256: .createPluginListForRepositories(repo);
257: PluginXmlUtil.writePluginList(pluginList, out);
258: }
259:
260: private PluginInstaller getInstaller(Kernel kernel) {
261: Set names = kernel.listGBeans(new AbstractNameQuery(
262: PluginInstaller.class.getName()));
263: if (names.size() == 0) {
264: return null;
265: }
266: return (PluginInstaller) kernel.getProxyManager().createProxy(
267: (AbstractName) names.iterator().next(),
268: PluginInstaller.class);
269: }
270:
271: private void generateMavenFile(Kernel kernel, PrintWriter writer,
272: String groupId, String artifactId, boolean reply)
273: throws ParserConfigurationException, TransformerException {
274: ConfigurationManager mgr = ConfigurationUtil
275: .getConfigurationManager(kernel);
276: Artifact[] artifacts = mgr.getArtifactResolver()
277: .queryArtifacts(
278: new Artifact(groupId, artifactId,
279: (Version) null, null));
280: if (!reply) {
281: return;
282: }
283:
284: DocumentBuilderFactory factory = XmlUtil
285: .newDocumentBuilderFactory();
286: DocumentBuilder builder = factory.newDocumentBuilder();
287: Document doc = builder.newDocument();
288: Element root = doc.createElement("metadata");
289: doc.appendChild(root);
290: createText(doc, root, "groupId", groupId);
291: createText(doc, root, "artifactId", artifactId);
292: if (artifacts.length > 0) {
293: createText(doc, root, "version", artifacts[0].getVersion()
294: .toString());
295: }
296: Element versioning = doc.createElement("versioning");
297: root.appendChild(versioning);
298: Element versions = doc.createElement("versions");
299: versioning.appendChild(versions);
300: for (int i = 0; i < artifacts.length; i++) {
301: Artifact artifact = artifacts[i];
302: createText(doc, versions, "version", artifact.getVersion()
303: .toString());
304: }
305: TransformerFactory xfactory = XmlUtil.newTransformerFactory();
306: Transformer xform = xfactory.newTransformer();
307: xform.setOutputProperty(OutputKeys.INDENT, "yes");
308: xform.transform(new DOMSource(doc), new StreamResult(writer));
309: }
310:
311: private void createText(Document doc, Element parent, String name,
312: String text) {
313: Element child = doc.createElement(name);
314: parent.appendChild(child);
315: Text node = doc.createTextNode(text);
316: child.appendChild(node);
317: }
318:
319: }
|