Author: [email protected]
Date: Tue Apr 5 19:11:00 2011
New Revision: 945
Log:
[sandbox] Proper handling of contexpath / wrapping requests
Modified:
branches/AMDATU-283-dev/amdatu-example/course-service/pom.xml
branches/AMDATU-283-dev/amdatu-example/course-service/src/main/java/org/amdatu/example/course/service/osgi/Activator.java
branches/AMDATU-283-dev/amdatu-opensocial/gadgetmanagement/src/main/java/org/amdatu/opensocial/gadgetmanagement/osgi/Activator.java
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/dispatch/CustomFilterPipeline.java
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/dispatch/ExtenderFilterChain.java
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/dispatch/ExtenderFilterPipeline.java
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/handler/FilterHandler.java
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/handler/ServletHandler.java
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/handler/ServletHandlerRegistry.java
branches/AMDATU-283-dev/amdatu-web/jsp/src/main/java/org/amdatu/web/jsp/service/ResourceProviderJspServlet.java
branches/AMDATU-283-dev/amdatu-web/resource/src/main/java/org/amdatu/web/resource/service/ResourceProviderListener.java
branches/AMDATU-283-dev/amdatu-web/resource/src/main/java/org/amdatu/web/resource/service/ResourceServlet.java
branches/AMDATU-283-dev/amdatu-web/rest-wink/src/main/java/org/amdatu/web/rest/wink/service/WinkServletFilter.java
Modified: branches/AMDATU-283-dev/amdatu-example/course-service/pom.xml
==============================================================================
--- branches/AMDATU-283-dev/amdatu-example/course-service/pom.xml
(original)
+++ branches/AMDATU-283-dev/amdatu-example/course-service/pom.xml Tue Apr
5 19:11:00 2011
@@ -21,6 +21,13 @@
<type>bundle</type>
</dependency>
<dependency>
+ <groupId>org.amdatu.web</groupId>
+ <artifactId>resource</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ <type>bundle</type>
+ </dependency>
+ <dependency>
<groupId>org.amdatu.web.rest</groupId>
<artifactId>jaxrs</artifactId>
<version>${project.version}</version>
Modified:
branches/AMDATU-283-dev/amdatu-example/course-service/src/main/java/org/amdatu/example/course/service/osgi/Activator.java
==============================================================================
---
branches/AMDATU-283-dev/amdatu-example/course-service/src/main/java/org/amdatu/example/course/service/osgi/Activator.java
(original)
+++
branches/AMDATU-283-dev/amdatu-example/course-service/src/main/java/org/amdatu/example/course/service/osgi/Activator.java
Tue Apr 5 19:11:00 2011
@@ -30,6 +30,7 @@
import org.amdatu.opensocial.profile.PersonService;
import org.amdatu.web.dispatcher.DispatcherService;
import org.amdatu.web.httpcontext.ResourceProvider;
+import org.amdatu.web.resource.ResourceSupport;
import org.amdatu.web.rest.jaxrs.JaxRsSpi;
import org.apache.felix.dm.DependencyManager;
import org.ontoware.rdf2go.model.ModelSet;
@@ -48,9 +49,6 @@
public final static String CONTEXTID = "amdatu-examples";
public final static String ALIAS = "/examples/course";
- public final static String JSP_ALIAS = ALIAS + "/jsp";
- public final static String RES_ALIAS = ALIAS + "/static";
-
@Override
protected Class<?>[] getRequiredServices() {
return new Class<?>[] { JaxRsSpi.class };
@@ -71,6 +69,7 @@
// Create and register the REST interface for the course service
Dictionary<String, Object> properties = new Hashtable<String,
Object>();
properties.put(DispatcherService.CONTEXT_ID_KEY, CONTEXTID);
+ properties.put(ResourceSupport.RESOURCE_ALIAS_KEY, ALIAS);
manager.add(
createComponent()
.setInterface(ResourceProvider.class.getName(), properties)
Modified:
branches/AMDATU-283-dev/amdatu-opensocial/gadgetmanagement/src/main/java/org/amdatu/opensocial/gadgetmanagement/osgi/Activator.java
==============================================================================
---
branches/AMDATU-283-dev/amdatu-opensocial/gadgetmanagement/src/main/java/org/amdatu/opensocial/gadgetmanagement/osgi/Activator.java
(original)
+++
branches/AMDATU-283-dev/amdatu-opensocial/gadgetmanagement/src/main/java/org/amdatu/opensocial/gadgetmanagement/osgi/Activator.java
Tue Apr 5 19:11:00 2011
@@ -70,7 +70,7 @@
// Provide context and alias information for resources
Dictionary<String, Object> properties = new Hashtable<String,
Object>();
properties.put(DispatcherService.CONTEXT_ID_KEY, CONTEXTID);
- properties.put(ResourceSupport.RESOURCE_ALIAS_KEY, ALIAS);
+ properties.put(ResourceSupport.RESOURCE_ALIAS_KEY, RES_ALIAS);
manager.add(
createAdapterService(UserAdmin.class, userAdminfilter)
Modified:
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/dispatch/CustomFilterPipeline.java
==============================================================================
---
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/dispatch/CustomFilterPipeline.java
(original)
+++
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/dispatch/CustomFilterPipeline.java
Tue Apr 5 19:11:00 2011
@@ -52,15 +52,51 @@
FilterHandler[] filterHandlers =
m_filterHandlerRegistry.getFilterHandlers(httpServletRequest);
ServletHandler[] servletHandlers =
m_servletHandlerRegistry.getServletHandlers(httpServletRequest);
- m_servletPipeline = new CustomServletPipeline(servletHandlers);
+
+ String localRequestUri = httpServletRequest.getRequestURI();
+ if (!httpServletRequest.getContextPath().equals("")) {
+ localRequestUri =
localRequestUri.replaceFirst(httpServletRequest.getContextPath(), "");
+ }
+
+ ServletHandler target = null;
+ for (ServletHandler handler : servletHandlers) {
+ if (handler.isActive() && handler.matches(localRequestUri)) {
+ target = handler;
+ break;
+ }
+ }
+
+ if (target == null) {
+ httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+
+ m_servletPipeline = new CustomServletPipeline(new ServletHandler[] {
target });
FilterChain chain = new CustomFilterChain(filterHandlers,
m_servletPipeline, proceedingChain);
- chain.doFilter(new RequestWrapper(httpServletRequest),
httpServletResponse);
+ chain.doFilter(new DispatcherRequestWrapper(httpServletRequest,
target.getAlias()), httpServletResponse);
}
- private final class RequestWrapper extends HttpServletRequestWrapper {
- public RequestWrapper(HttpServletRequest httpServletRequest) {
+ private final class DispatcherRequestWrapper extends
HttpServletRequestWrapper {
+
+ private final String m_pathInfo;
+ private final String m_servletPath;
+
+ public DispatcherRequestWrapper(HttpServletRequest httpServletRequest,
String servletAlias) {
super(httpServletRequest);
+
+ m_servletPath = httpServletRequest.getContextPath() + servletAlias;
+ m_pathInfo =
httpServletRequest.getPathInfo().replaceFirst(servletAlias, "");
+ }
+
+ @Override
+ public String getPathInfo() {
+ return m_pathInfo;
+ }
+
+ @Override
+ public String getServletPath() {
+ return m_servletPath;
}
@Override
Modified:
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/dispatch/ExtenderFilterChain.java
==============================================================================
---
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/dispatch/ExtenderFilterChain.java
(original)
+++
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/dispatch/ExtenderFilterChain.java
Tue Apr 5 19:11:00 2011
@@ -27,7 +27,7 @@
/**
* Custom <code>FilterChain</code> implementation that invokes an array of
<code>FilterHandler</code>
- * instances wrapping <code>ExternderFilter</code> objects and continues on to
the specified <code>
+ * instances wrapping <code>ExtenderFilter</code> objects and continues on to
the specified <code>
* TenantFilterPipeline</code>.
*/
public final class ExtenderFilterChain extends HttpFilterChain {
Modified:
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/dispatch/ExtenderFilterPipeline.java
==============================================================================
---
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/dispatch/ExtenderFilterPipeline.java
(original)
+++
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/dispatch/ExtenderFilterPipeline.java
Tue Apr 5 19:11:00 2011
@@ -19,10 +19,8 @@
import java.io.IOException;
import javax.servlet.FilterChain;
-import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import org.amdatu.web.dispatcher.handler.FilterHandler;
@@ -44,17 +42,6 @@
public void dispatch(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
FilterChain proceedingChain) throws ServletException, IOException {
FilterChain chain = new ExtenderFilterChain(m_filterHandlers,
m_tenantFilterPipeline, proceedingChain);
- chain.doFilter(new RequestWrapper(httpServletRequest),
httpServletResponse);
- }
-
- private final class RequestWrapper extends HttpServletRequestWrapper {
- public RequestWrapper(HttpServletRequest req) {
- super(req);
- }
-
- @Override
- public RequestDispatcher getRequestDispatcher(String path) {
- return null;
- }
+ chain.doFilter(httpServletRequest, httpServletResponse);
}
}
\ No newline at end of file
Modified:
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/handler/FilterHandler.java
==============================================================================
---
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/handler/FilterHandler.java
(original)
+++
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/handler/FilterHandler.java
Tue Apr 5 19:11:00 2011
@@ -65,7 +65,13 @@
public void handle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
FilterChain filterChain) throws ServletException, IOException {
- if (isActive() && matches(httpServletRequest.getPathInfo())) {
+
+ String localRequestUri = httpServletRequest.getRequestURI();
+ if (!httpServletRequest.getContextPath().equals("")) {
+ localRequestUri =
localRequestUri.replaceFirst(httpServletRequest.getContextPath(), "");
+ }
+
+ if (isActive() && matches(localRequestUri)) {
doHandle(httpServletRequest, httpServletResponse, filterChain);
return;
}
Modified:
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/handler/ServletHandler.java
==============================================================================
---
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/handler/ServletHandler.java
(original)
+++
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/handler/ServletHandler.java
Tue Apr 5 19:11:00 2011
@@ -61,7 +61,13 @@
public boolean handle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse)
throws ServletException, IOException {
- if (isActive() && matches(httpServletRequest.getRequestURI())) {
+
+ String localRequestUri = httpServletRequest.getRequestURI();
+ if (!httpServletRequest.getContextPath().equals("")) {
+ localRequestUri =
localRequestUri.replaceFirst(httpServletRequest.getContextPath(), "");
+ }
+
+ if (isActive() && matches(localRequestUri)) {
doHandle(httpServletRequest, httpServletResponse);
return true;
}
@@ -100,7 +106,7 @@
}
}
else {
- m_servlet.service(new ServletHandlerRequest(httpServletRequest,
m_alias), httpServletResponse);
+ m_servlet.service(httpServletRequest, httpServletResponse);
}
}
}
Modified:
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/handler/ServletHandlerRegistry.java
==============================================================================
---
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/handler/ServletHandlerRegistry.java
(original)
+++
branches/AMDATU-283-dev/amdatu-web/dispatcher/src/main/java/org/amdatu/web/dispatcher/handler/ServletHandlerRegistry.java
Tue Apr 5 19:11:00 2011
@@ -111,7 +111,8 @@
String alias = getStringProperty(serviceReference,
DispatcherServiceImpl.ALIAS_KEY);
if (alias == null) {
if (getLogService() != null)
- getLogService().log(LogService.LOG_WARNING, "Cannot register a
servlet without alias");
+ getLogService().log(LogService.LOG_WARNING,
+ "Cannot register a servlet without alias (" +
Constants.SERVICE_ID + "=" + serviceId + ")");
return;
}
@@ -125,7 +126,7 @@
if (m_servletHandlers.containsKey(serviceReference)) {
throw new IllegalStateException("Unexpected.... ");
}
-
+
HttpContext context = getHttpContext(contextId,
serviceReference.getBundle());
if (context != null) {
HandlerServletContext servletContextWrapper =
Modified:
branches/AMDATU-283-dev/amdatu-web/jsp/src/main/java/org/amdatu/web/jsp/service/ResourceProviderJspServlet.java
==============================================================================
---
branches/AMDATU-283-dev/amdatu-web/jsp/src/main/java/org/amdatu/web/jsp/service/ResourceProviderJspServlet.java
(original)
+++
branches/AMDATU-283-dev/amdatu-web/jsp/src/main/java/org/amdatu/web/jsp/service/ResourceProviderJspServlet.java
Tue Apr 5 19:11:00 2011
@@ -114,8 +114,13 @@
* @see ResourceProviderJspServlet#service(ServletRequest, ServletResponse)
*/
public void service(final ServletRequest req, final ServletResponse res)
throws ServletException, IOException {
- HttpServletRequest request = (HttpServletRequest) req;
- req.setAttribute(Constants.JSP_FILE, request.getRequestURI());
+
+ final HttpServletRequest httpServletRequest = (HttpServletRequest) req;
+ String target = httpServletRequest.getRequestURI();
+ if(!httpServletRequest.getContextPath().equals("")){
+ target = target.replaceFirst(httpServletRequest.getContextPath(),
"");
+ }
+ req.setAttribute(Constants.JSP_FILE, target);
try {
ContextClassLoaderUtils.doWithClassLoader(
Modified:
branches/AMDATU-283-dev/amdatu-web/resource/src/main/java/org/amdatu/web/resource/service/ResourceProviderListener.java
==============================================================================
---
branches/AMDATU-283-dev/amdatu-web/resource/src/main/java/org/amdatu/web/resource/service/ResourceProviderListener.java
(original)
+++
branches/AMDATU-283-dev/amdatu-web/resource/src/main/java/org/amdatu/web/resource/service/ResourceProviderListener.java
Tue Apr 5 19:11:00 2011
@@ -98,7 +98,7 @@
Component servletComponent = m_dependencyManager.createComponent();
servletComponent.setInterface(Servlet.class.getName(), properties);
- servletComponent.setImplementation(new ResourceServlet(resourceAlias));
+ servletComponent.setImplementation(new ResourceServlet());
return servletComponent;
}
Modified:
branches/AMDATU-283-dev/amdatu-web/resource/src/main/java/org/amdatu/web/resource/service/ResourceServlet.java
==============================================================================
---
branches/AMDATU-283-dev/amdatu-web/resource/src/main/java/org/amdatu/web/resource/service/ResourceServlet.java
(original)
+++
branches/AMDATU-283-dev/amdatu-web/resource/src/main/java/org/amdatu/web/resource/service/ResourceServlet.java
Tue Apr 5 19:11:00 2011
@@ -1,18 +1,18 @@
/*
- * 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.
+ 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;
@@ -29,15 +29,17 @@
public final class ResourceServlet extends HttpServlet {
- private final String path;
-
- public ResourceServlet(String path) {
- this.path = path;
+ public ResourceServlet() {
}
@Override
- protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
- String target = req.getPathInfo();
+ protected void doGet(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) throws ServletException, IOException {
+
+ String target = httpServletRequest.getRequestURI();
+ if(!httpServletRequest.getContextPath().equals("")){
+ target = target.replaceFirst(httpServletRequest.getContextPath(),
"");
+ }
+
if (target == null) {
target = "";
}
@@ -46,33 +48,31 @@
target += "/" + target;
}
- String resName = this.path + target;
- URL url = getServletContext().getResource(resName);
-
+ URL url = getServletContext().getResource(target);
if (url == null) {
- res.sendError(HttpServletResponse.SC_NOT_FOUND);
+ httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
}
else {
- handle(req, res, url, resName);
+ handle(httpServletRequest, httpServletResponse, url, target);
}
}
- private void handle(HttpServletRequest req, HttpServletResponse res, URL
url, String resName) throws IOException {
+ private void handle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, URL url, String resName) throws
IOException {
String contentType = getServletContext().getMimeType(resName);
if (contentType != null) {
- res.setContentType(contentType);
+ httpServletResponse.setContentType(contentType);
}
long lastModified = getLastModified(url);
if (lastModified != 0) {
- res.setDateHeader("Last-Modified", lastModified);
+ httpServletResponse.setDateHeader("Last-Modified", lastModified);
}
- if (!resourceModified(lastModified,
req.getDateHeader("If-Modified-Since"))) {
- res.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+ if (!resourceModified(lastModified,
httpServletRequest.getDateHeader("If-Modified-Since"))) {
+ httpServletResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
else {
- copyResource(url, res);
+ copyResource(url, httpServletResponse);
}
}
Modified:
branches/AMDATU-283-dev/amdatu-web/rest-wink/src/main/java/org/amdatu/web/rest/wink/service/WinkServletFilter.java
==============================================================================
---
branches/AMDATU-283-dev/amdatu-web/rest-wink/src/main/java/org/amdatu/web/rest/wink/service/WinkServletFilter.java
(original)
+++
branches/AMDATU-283-dev/amdatu-web/rest-wink/src/main/java/org/amdatu/web/rest/wink/service/WinkServletFilter.java
Tue Apr 5 19:11:00 2011
@@ -21,12 +21,11 @@
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
-import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletRequestWrapper;
/**
* The Wink servlet filter has only one purpose; getting rid of the double
path occurrence in the URLs of the
@@ -62,37 +61,51 @@
m_dispatchTo = to;
}
+ public void init(FilterConfig filterConfig) throws ServletException {
+ }
+
+ public void destroy() {
+ }
+
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException,
ServletException {
- String path = ((HttpServletRequest) request).getRequestURI();
- String contextPath = ((HttpServletRequest) request).getContextPath();
- if (contextPath != null && !contextPath.isEmpty()) {
- // Remove context path from the URI before dispatching it
- path = path.substring(contextPath.length());
- }
-
- // To prevent endless recursion we verify that the path doesn't start
with our target path. There is one
- // situation in which this fails; the case that a rest service with
path 'example' also annotates one of
- // its methods with 'example'. In this case /rest/example/example
should be forwarded to /rest/example/example/example,
- // but it's not.
- if (path.startsWith(m_dispatchFrom) && !path.startsWith(m_dispatchTo))
{
- String targetPath = path.replace(m_dispatchFrom, m_dispatchTo);
- RequestDispatcher dispatcher =
request.getRequestDispatcher(targetPath);
- if (dispatcher == null) {
- ((HttpServletResponse)
response).sendError(HttpServletResponse.SC_NOT_FOUND);
- }
- else {
- dispatcher.forward(request, response);
- }
+
+ HttpServletRequest httpServletRequest = (HttpServletRequest) request;
+ final String servletPath = httpServletRequest.getServletPath();
+
+ if (servletPath.endsWith(m_dispatchFrom)) {
+ String targetPath = servletPath.replace(m_dispatchFrom,
m_dispatchTo);
+ chain.doFilter(new
WinkServletFilterRequestWrapper(httpServletRequest, targetPath), response);
}
else {
chain.doFilter(request, response);
}
}
- public void destroy() {
- }
+ private final class WinkServletFilterRequestWrapper extends
HttpServletRequestWrapper {
- public void init(FilterConfig filterConfig) throws ServletException {
+ private final String m_servletPath;
+ private final String m_requestUri;
+
+ public WinkServletFilterRequestWrapper(HttpServletRequest req, String
servletPath) {
+ super(req);
+ m_servletPath = servletPath;
+ m_requestUri = servletPath + req.getPathInfo();
+ }
+
+ @Override
+ public String getPathInfo() {
+ return super.getPathInfo();
+ }
+
+ @Override
+ public String getRequestURI() {
+ return m_requestUri;
+ }
+
+ @Override
+ public String getServletPath() {
+ return super.getServletPath();
+ }
}
}
_______________________________________________
Amdatu-commits mailing list
[email protected]
http://lists.amdatu.org/mailman/listinfo/amdatu-commits