]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms/src/org/argeo/cms/internal/http/PkgServlet.java
Close release cycle
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / internal / http / PkgServlet.java
1 package org.argeo.cms.internal.http;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.net.URL;
6 import java.util.Collection;
7 import java.util.Enumeration;
8 import java.util.SortedMap;
9 import java.util.TreeMap;
10
11 import javax.servlet.ServletException;
12 import javax.servlet.http.HttpServlet;
13 import javax.servlet.http.HttpServletRequest;
14 import javax.servlet.http.HttpServletResponse;
15
16 import org.apache.commons.io.IOUtils;
17 import org.argeo.api.PublishNamespace;
18 import org.argeo.osgi.util.FilterRequirement;
19 import org.osgi.framework.Bundle;
20 import org.osgi.framework.BundleContext;
21 import org.osgi.framework.FrameworkUtil;
22 import org.osgi.framework.Version;
23 import org.osgi.framework.VersionRange;
24 import org.osgi.framework.namespace.PackageNamespace;
25 import org.osgi.framework.wiring.BundleCapability;
26 import org.osgi.framework.wiring.BundleWiring;
27 import org.osgi.framework.wiring.FrameworkWiring;
28 import org.osgi.resource.Requirement;
29
30 public class PkgServlet extends HttpServlet {
31 private static final long serialVersionUID = 7660824185145214324L;
32
33 private BundleContext bundleContext = FrameworkUtil.getBundle(PkgServlet.class).getBundleContext();
34
35 @Override
36 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
37 String pathInfo = req.getPathInfo();
38
39 String pkg, versionStr, file;
40 String[] parts = pathInfo.split("/");
41 // first is always empty
42 if (parts.length == 4) {
43 pkg = parts[1];
44 versionStr = parts[2];
45 file = parts[3];
46 } else if (parts.length == 3) {
47 pkg = parts[1];
48 versionStr = null;
49 file = parts[2];
50 } else {
51 throw new IllegalArgumentException("Unsupported path length " + pathInfo);
52 }
53
54 FrameworkWiring frameworkWiring = bundleContext.getBundle(0).adapt(FrameworkWiring.class);
55 String filter;
56 if (versionStr == null) {
57 filter = "(" + PackageNamespace.PACKAGE_NAMESPACE + "=" + pkg + ")";
58 } else {
59 if (versionStr.startsWith("[") || versionStr.startsWith("(")) {// range
60 VersionRange versionRange = new VersionRange(versionStr);
61 filter = "(&(" + PackageNamespace.PACKAGE_NAMESPACE + "=" + pkg + ")"
62 + versionRange.toFilterString(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE) + ")";
63
64 } else {
65 Version version = new Version(versionStr);
66 filter = "(&(" + PackageNamespace.PACKAGE_NAMESPACE + "=" + pkg + ")("
67 + PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE + "=" + version + "))";
68 }
69 }
70 Requirement requirement = new FilterRequirement(PackageNamespace.PACKAGE_NAMESPACE, filter);
71 Collection<BundleCapability> packages = frameworkWiring.findProviders(requirement);
72 if (packages.isEmpty()) {
73 resp.sendError(404);
74 return;
75 }
76
77 // TODO verify that it works with multiple versions
78 SortedMap<Version, BundleCapability> sorted = new TreeMap<>();
79 for (BundleCapability capability : packages) {
80 sorted.put(capability.getRevision().getVersion(), capability);
81 }
82
83 Bundle bundle = sorted.get(sorted.firstKey()).getRevision().getBundle();
84 String entryPath = '/' + pkg.replace('.', '/') + '/' + file;
85 URL internalURL = bundle.getResource(entryPath);
86 if (internalURL == null) {
87 resp.sendError(404);
88 return;
89 }
90
91 // Resource found, we now check whether it can be published
92 boolean publish = false;
93 BundleWiring bundleWiring = bundle.adapt(BundleWiring.class);
94 capabilities: for (BundleCapability bundleCapability : bundleWiring
95 .getCapabilities(PublishNamespace.CMS_PUBLISH_NAMESPACE)) {
96 Object publishedPkg = bundleCapability.getAttributes().get(PublishNamespace.PKG);
97 if (publishedPkg != null) {
98 if (publishedPkg.equals("*") || publishedPkg.equals(pkg)) {
99 Object publishedFile = bundleCapability.getAttributes().get(PublishNamespace.FILE);
100 if (publishedFile == null) {
101 publish = true;
102 break capabilities;
103 } else {
104 String[] publishedFiles = publishedFile.toString().split(",");
105 for (String pattern : publishedFiles) {
106 if (pattern.startsWith("*.")) {
107 String ext = pattern.substring(1);
108 if (file.endsWith(ext)) {
109 publish = true;
110 break capabilities;
111 }
112 } else {
113 if (publishedFile.equals(file)) {
114 publish = true;
115 break capabilities;
116 }
117 }
118 }
119 }
120 }
121 }
122 }
123
124 if (!publish) {
125 resp.sendError(404);
126 return;
127 }
128
129 try (InputStream in = internalURL.openStream()) {
130 IOUtils.copy(in, resp.getOutputStream());
131 }
132 }
133
134 }