Author: bdekruijff at gmail.com
Date: Mon Jan 31 11:08:15 2011
New Revision: 721

Log:
AMDATU-245 add resource extender module

Added:
   branches/amdatu-dispatcher/amdatu-web/resource/
   branches/amdatu-dispatcher/amdatu-web/resource/pom.xml
   branches/amdatu-dispatcher/amdatu-web/resource/src/
   branches/amdatu-dispatcher/amdatu-web/resource/src/main/
   branches/amdatu-dispatcher/amdatu-web/resource/src/main/java/
   branches/amdatu-dispatcher/amdatu-web/resource/src/main/java/org/
   branches/amdatu-dispatcher/amdatu-web/resource/src/main/java/org/amdatu/
   branches/amdatu-dispatcher/amdatu-web/resource/src/main/java/org/amdatu/web/
   
branches/amdatu-dispatcher/amdatu-web/resource/src/main/java/org/amdatu/web/resource/
   
branches/amdatu-dispatcher/amdatu-web/resource/src/main/java/org/amdatu/web/resource/osgi/
   
branches/amdatu-dispatcher/amdatu-web/resource/src/main/java/org/amdatu/web/resource/osgi/Activator.java
   
branches/amdatu-dispatcher/amdatu-web/resource/src/main/java/org/amdatu/web/resource/service/
   
branches/amdatu-dispatcher/amdatu-web/resource/src/main/java/org/amdatu/web/resource/service/ResourceProviderListener.java
   
branches/amdatu-dispatcher/amdatu-web/resource/src/main/java/org/amdatu/web/resource/service/ResourceServlet.java
Modified:
   branches/amdatu-dispatcher/amdatu-web/pom.xml

Modified: branches/amdatu-dispatcher/amdatu-web/pom.xml
==============================================================================
--- branches/amdatu-dispatcher/amdatu-web/pom.xml       (original)
+++ branches/amdatu-dispatcher/amdatu-web/pom.xml       Mon Jan 31 11:08:15 2011
@@ -41,6 +41,7 @@
 
   <modules>
     <module>dispatcher</module>
+    <module>resource</module>
     <module>httpcontext</module>
     <module>jsp</module>
     <module>rest-jaxrs</module>

Added: branches/amdatu-dispatcher/amdatu-web/resource/pom.xml
==============================================================================
--- (empty file)
+++ branches/amdatu-dispatcher/amdatu-web/resource/pom.xml      Mon Jan 31 
11:08:15 2011
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.amdatu</groupId>
+    <artifactId>org.amdatu.web</artifactId>
+    <version>0.1.0-SNAPSHOT</version>
+  </parent>
+  <groupId>org.amdatu.web</groupId>
+  <artifactId>resource</artifactId>
+  <packaging>bundle</packaging>
+  <name>Amdatu Web - Resource Support</name>
+  <description>Bundle providing Resource support</description>
+  
+  <dependencies>
+    <dependency>
+      <groupId>org.amdatu.web</groupId>
+      <artifactId>httpcontext</artifactId>
+      <scope>provided</scope>
+      <type>bundle</type>
+    </dependency>
+  </dependencies>
+  
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <configuration>
+          <instructions>
+            
<Bundle-Activator>org.amdatu.web.resource.osgi.Activator</Bundle-Activator>
+            <Bundle-SymbolicName>org.amdatu.web.resource</Bundle-SymbolicName> 
       
+            <Embed-Dependency>*;scope=compile</Embed-Dependency>
+            <Embed-Transitive>true</Embed-Transitive>
+            <Export-Package></Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>   
+    </plugins>        
+  </build> 
+
+</project>

Added: 
branches/amdatu-dispatcher/amdatu-web/resource/src/main/java/org/amdatu/web/resource/osgi/Activator.java
==============================================================================
--- (empty file)
+++ 
branches/amdatu-dispatcher/amdatu-web/resource/src/main/java/org/amdatu/web/resource/osgi/Activator.java
    Mon Jan 31 11:08:15 2011
@@ -0,0 +1,46 @@
+/*
+    Copyright (C) 2010 Amdatu.org
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.web.resource.osgi;
+
+import org.amdatu.web.httpcontext.ResourceProvider;
+import org.amdatu.web.resource.service.ResourceProviderListener;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+
+/**
+ * This is the activator for the resource support bundle.
+ */
+public class Activator extends DependencyActivatorBase {
+    public final static String RESOURCE_ID = "resourceservlet";
+
+    @Override
+    public void init(BundleContext context, DependencyManager manager) throws 
Exception {
+        manager.add(
+            createComponent()
+                .setImplementation(ResourceProviderListener.class)
+                
.add(createServiceDependency().setService(LogService.class).setRequired(true))
+                
.add(createServiceDependency().setService(ResourceProvider.class)
+                    .setRequired(false)
+                    .setCallbacks("resourceProviderAdded", 
"resourceProviderRemoved")));
+    }
+
+    @Override
+    public void destroy(BundleContext context, DependencyManager manager) 
throws Exception {
+    }
+}

Added: 
branches/amdatu-dispatcher/amdatu-web/resource/src/main/java/org/amdatu/web/resource/service/ResourceProviderListener.java
==============================================================================
--- (empty file)
+++ 
branches/amdatu-dispatcher/amdatu-web/resource/src/main/java/org/amdatu/web/resource/service/ResourceProviderListener.java
  Mon Jan 31 11:08:15 2011
@@ -0,0 +1,97 @@
+/*
+    Copyright (C) 2010 Amdatu.org
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.web.resource.service;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import javax.servlet.Servlet;
+
+import org.amdatu.web.httpcontext.ResourceProvider;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+
+/**
+ * This class is responsible for registration of Resource Servlets for each
+ * ResourceProvider that comes available.
+ */
+public class ResourceProviderListener {
+
+    private final Map<String, Component> m_servletComponents = new 
HashMap<String, Component>();
+
+    private volatile DependencyManager m_dependencyManager;
+    private volatile BundleContext m_bundleContext;
+    private volatile LogService m_logService;
+
+    public void init() {
+    }
+
+    public void start() {
+    }
+
+    public void stop() {
+    }
+
+    public void destroy() {
+    }
+
+    public void resourceProviderAdded(ServiceReference serviceReference, 
ResourceProvider resourceProvider) {
+
+        Dictionary<String, Object> properties = new Hashtable<String, 
Object>();
+        properties.put("contextId", resourceProvider.getResourceId());
+        properties.put("alias", 
getResourceAlias(resourceProvider.getResourceId()));
+
+        Component servletComponent = m_dependencyManager.createComponent();
+        servletComponent.setInterface(Servlet.class.getName(), properties);
+        servletComponent.setImplementation(new ResourceServlet(""));
+
+        m_dependencyManager.add(servletComponent);
+        m_servletComponents.put(resourceProvider.getResourceId(), 
servletComponent);
+
+        m_logService.log(LogService.LOG_DEBUG,
+            "Resource servlet added for resource provider " + 
resourceProvider.getResourceId());
+    }
+
+    public void resourceProviderRemoved(ResourceProvider resourceProvider) {
+
+        Component servletComponent = 
m_servletComponents.remove(resourceProvider.getResourceId());
+        if (servletComponent != null)
+            m_dependencyManager.remove(servletComponent);
+
+        m_logService.log(LogService.LOG_DEBUG,
+            "Resource servlet removed for resource provider " + 
resourceProvider.getResourceId());
+    }
+
+    private String getResourceAlias(String resourceId) {
+        String result = "";
+        if (!resourceId.startsWith("/")) {
+            result = "/" + resourceId;
+        }
+        else {
+            result = resourceId;
+        }
+        if (resourceId.endsWith("/")) {
+            result = result.substring(0, result.length() - 1);
+        }
+        return result;
+    }
+}
\ No newline at end of file

Added: 
branches/amdatu-dispatcher/amdatu-web/resource/src/main/java/org/amdatu/web/resource/service/ResourceServlet.java
==============================================================================
--- (empty file)
+++ 
branches/amdatu-dispatcher/amdatu-web/resource/src/main/java/org/amdatu/web/resource/service/ResourceServlet.java
   Mon Jan 31 11:08:15 2011
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.amdatu.web.resource.service;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.ServletException;
+import java.io.IOException;
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.net.URLConnection;
+
+public final class ResourceServlet extends HttpServlet {
+
+    private final String path;
+
+    public ResourceServlet(String path) {
+        this.path = path;
+    }
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse res) 
throws ServletException, IOException {
+        String target = req.getPathInfo();
+        if (target == null) {
+            target = "";
+        }
+
+        if (!target.startsWith("/")) {
+            target += "/" + target;
+        }
+
+        String resName = this.path + target;
+        URL url = getServletContext().getResource(resName);
+
+        if (url == null) {
+            res.sendError(HttpServletResponse.SC_NOT_FOUND);
+        }
+        else {
+            handle(req, res, url, resName);
+        }
+    }
+
+    private void handle(HttpServletRequest req, HttpServletResponse res, URL 
url, String resName) throws IOException {
+        String contentType = getServletContext().getMimeType(resName);
+        if (contentType != null) {
+            res.setContentType(contentType);
+        }
+
+        long lastModified = getLastModified(url);
+        if (lastModified != 0) {
+            res.setDateHeader("Last-Modified", lastModified);
+        }
+
+        if (!resourceModified(lastModified, 
req.getDateHeader("If-Modified-Since"))) {
+            res.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+        }
+        else {
+            copyResource(url, res);
+        }
+    }
+
+    private long getLastModified(URL url) {
+        long lastModified = 0;
+
+        try {
+            URLConnection conn = url.openConnection();
+            lastModified = conn.getLastModified();
+        }
+        catch (Exception e) {
+            // Do nothing
+        }
+
+        if (lastModified == 0) {
+            String filepath = url.getPath();
+            if (filepath != null) {
+                File f = new File(filepath);
+                if (f.exists()) {
+                    lastModified = f.lastModified();
+                }
+            }
+        }
+
+        return lastModified;
+    }
+
+    private boolean resourceModified(long resTimestamp, long modSince) {
+        modSince /= 1000;
+        resTimestamp /= 1000;
+
+        return resTimestamp == 0 || modSince == -1 || resTimestamp > modSince;
+    }
+
+    private void copyResource(URL url, HttpServletResponse res)
+        throws IOException {
+        OutputStream os = null;
+        InputStream is = null;
+
+        try {
+            os = res.getOutputStream();
+            is = url.openStream();
+
+            int len = 0;
+            byte[] buf = new byte[1024];
+            int n;
+
+            while ((n = is.read(buf, 0, buf.length)) >= 0) {
+                os.write(buf, 0, n);
+                len += n;
+            }
+
+            res.setContentLength(len);
+        }
+        finally {
+            if (is != null) {
+                is.close();
+            }
+
+            if (os != null) {
+                os.close();
+            }
+        }
+    }
+}

Reply via email to