CQ-3581 jetty-osgi contribution from Hugues Malphettes of intalio

git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@1023 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
Greg Wilkins 2009-11-02 22:49:53 +00:00
parent b170e765f3
commit ebdc841479
87 changed files with 6665 additions and 0 deletions

View File

@ -0,0 +1,19 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Jetty-OSGi-Jasper integration
Fragment-Host: org.eclipse.jetty.osgi.boot
Bundle-SymbolicName: org.eclipse.jetty.osgi.boot.jasper;singleton:=true
Bundle-Version: 7.0.1.qualifier
Bundle-Vendor: Intalio Inc
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Require-Bundle: org.mortbay.jetty.jsp-2.1;bundle-version="[7.0,8)",
org.mortbay.jetty.jsp-2.1-glassfish;bundle-version="9.1.1"
Import-Package: javax.el;version="2.1",
javax.servlet.jsp;version="2.1",
javax.servlet.jsp.el;version="2.1",
javax.servlet.jsp.jstl.core;version="2.1",
javax.servlet.jsp.jstl.fmt;version="2.1",
javax.servlet.jsp.jstl.sql;version="2.1",
javax.servlet.jsp.jstl.tlv;version="2.1",
javax.servlet.jsp.resources;version="2.1",
javax.servlet.jsp.tagext;version="2.1"

View File

@ -0,0 +1,187 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.boot.jasper;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import javax.servlet.jsp.JspContext;
import org.apache.jasper.Constants;
import org.apache.jasper.compiler.Localizer;
import org.apache.jasper.compiler.TldLocationsCache;
import org.apache.jasper.xmlparser.ParserUtils;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
import org.eclipse.jetty.osgi.boot.utils.WebappRegistrationCustomizer;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Fix various shortcomings with the way jasper parses the tld files.
*/
public class WebappRegistrationCustomizerImpl implements WebappRegistrationCustomizer
{
public WebappRegistrationCustomizerImpl()
{
fixupDtdResolution();
try
{
Class<?> cl = getClass().getClassLoader().loadClass(
"org.apache.jasper.servlet.JspServlet");
System.err.println("found the jsp servlet: " + cl.getName());
}
catch (ClassNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* TODO: right now only the jetty-jsp bundle is scanned for common taglibs. Should support a way to plug more bundles that contain taglibs.
*
* The jasper TldScanner expects a URLClassloader to parse a jar for the /META-INF/*.tld it may contain. We place the bundles that we know contain such
* tag-libraries. Please note that it will work if and only if the bundle is a jar (!) Currently we just hardcode the bundle that contains the jstl
* implemenation.
*
* A workaround when the tld cannot be parsed with this method is to copy and paste it inside the WEB-INF of the webapplication where it is used.
*
* Support only 2 types of packaging for the bundle: - the bundle is a jar (recommended for runtime.) - the bundle is a folder and contain jars in the root
* and/or in the lib folder (nice for PDE developement situations) Unsupported: the bundle is a jar that embeds more jars.
*
* @return
* @throws Exception
*/
public URL[] getJarsWithTlds(BundleFileLocatorHelper locatorHelper) throws Exception
{
Bundle jasperBundler = FrameworkUtil.getBundle(TldLocationsCache.class);
File jasperLocation = locatorHelper.getBundleInstallLocation(jasperBundler);
if (jasperLocation.isDirectory())
{
// try to find the jar files inside this folder
ArrayList<URL> urls = new ArrayList<URL>();
for (File f : jasperLocation.listFiles())
{
if (f.getName().endsWith(".jar") && f.isFile())
{
urls.add(f.toURI().toURL());
}
else if (f.isDirectory() && f.getName().equals("lib"))
{
for (File f2 : jasperLocation.listFiles())
{
if (f2.getName().endsWith(".jar") && f2.isFile())
{
urls.add(f2.toURI().toURL());
}
}
}
}
return urls.toArray(new URL[urls.size()]);
}
else
{
return new URL[] { jasperLocation.toURI().toURL() };
}
}
/**
* Jasper resolves the dtd when it parses a taglib descriptor.
* It uses this code to do that: ParserUtils.getClass().getResourceAsStream(resourcePath); where
* resourcePath is for example: /javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd Unfortunately,
* the dtd file is not in the exact same classloader as
* ParserUtils class and the dtds are packaged in 2 separate bundles.
* OSGi does not look in the dependencies' classloader when a resource is searched.
* <p>
* The workaround consists of setting the entity resolver. That is a patch
* added to the version of glassfish-jasper-jetty. IT is also present in the latest
* version of glassfish jasper. Could not use introspection to set new value
* on a static friendly field :(
* </p>
*/
void fixupDtdResolution()
{
try
{
ParserUtils.setEntityResolver(new MyFixedupEntityResolver());
}
catch (Exception e)
{
e.printStackTrace();
}
}
/**
* Instead of using the ParserUtil's classloader, we use a class that is indeed next to the resource for sure.
*/
static class MyFixedupEntityResolver implements EntityResolver
{
/**
* Same values than in ParserUtils...
*/
static final String[] CACHED_DTD_PUBLIC_IDS =
{ Constants.TAGLIB_DTD_PUBLIC_ID_11, Constants.TAGLIB_DTD_PUBLIC_ID_12,
Constants.WEBAPP_DTD_PUBLIC_ID_22, Constants.WEBAPP_DTD_PUBLIC_ID_23, };
static final String[] CACHED_DTD_RESOURCE_PATHS =
{ Constants.TAGLIB_DTD_RESOURCE_PATH_11,
Constants.TAGLIB_DTD_RESOURCE_PATH_12,
Constants.WEBAPP_DTD_RESOURCE_PATH_22,
Constants.WEBAPP_DTD_RESOURCE_PATH_23, };
// static final String[] CACHED_SCHEMA_RESOURCE_PATHS = {
// Constants.TAGLIB_SCHEMA_RESOURCE_PATH_20,
// Constants.TAGLIB_SCHEMA_RESOURCE_PATH_21,
// Constants.WEBAPP_SCHEMA_RESOURCE_PATH_24,
// Constants.WEBAPP_SCHEMA_RESOURCE_PATH_25,
// };
public InputSource resolveEntity(String publicId, String systemId) throws SAXException
{
for (int i = 0; i < CACHED_DTD_PUBLIC_IDS.length; i++)
{
String cachedDtdPublicId = CACHED_DTD_PUBLIC_IDS[i];
if (cachedDtdPublicId.equals(publicId))
{
String resourcePath = CACHED_DTD_RESOURCE_PATHS[i];
InputStream input = null;
input = JspContext.class.getResourceAsStream(resourcePath);
if (input == null)
{
// if that failed try again with the original code:
// although it is likely not changed.
input = this.getClass().getResourceAsStream(resourcePath);
}
if (input == null)
{
throw new SAXException(Localizer.getMessage("jsp.error.internal.filenotfound",resourcePath));
}
InputSource isrc = new InputSource(input);
return isrc;
}
}
return null;
}
}
}

View File

@ -0,0 +1,47 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Jetty OSGi bootstrap
Bundle-SymbolicName: org.eclipse.jetty.osgi.boot;singleton:=true
Bundle-Version: 7.0.1.qualifier
Bundle-Activator: org.eclipse.jetty.osgi.boot.JettyBootstrapActivator
Import-Package: javax.mail;resolution:=optional,
javax.mail.event;resolution:=optional,
javax.mail.internet;resolution:=optional,
javax.mail.search;resolution:=optional,
javax.mail.util;resolution:=optional,
javax.naming;resolution:=optional,
javax.naming.directory;resolution:=optional,
javax.security.auth;resolution:=optional,
javax.security.auth.callback;resolution:=optional,
javax.security.auth.login;resolution:=optional,
javax.security.auth.spi;resolution:=optional,
javax.servlet,
javax.servlet.http,
javax.transaction;version="1.1.0";resolution:=optional,
javax.transaction.xa;version="1.1.0";resolution:=optional,
org.osgi.framework,
org.osgi.service.cm;version="1.2.0",
org.osgi.service.startlevel;version="1.0",
org.xml.sax
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Require-Bundle: org.eclipse.jetty.ajp;bundle-version="[7.0,8)";resolution:=optional,
org.eclipse.jetty.annotations;bundle-version="[7.0,8)";resolution:=optional,
org.eclipse.jetty.client;bundle-version="[7.0,8)";resolution:=optional,
org.eclipse.jetty.continuation;bundle-version="[7.0,8)";resolution:=optional,
org.eclipse.jetty.deploy;bundle-version="[7.0,8)",
org.eclipse.jetty.http;bundle-version="[7.0,8)",
org.eclipse.jetty.io;bundle-version="[7.0,8)",
org.eclipse.jetty.jmx;bundle-version="[7.0,8)";resolution:=optional,
org.eclipse.jetty.jndi;bundle-version="[7.0,8)";resolution:=optional,
org.eclipse.jetty.plus;bundle-version="[7.0,8.0)";resolution:=optional,
org.eclipse.jetty.rewrite;bundle-version="[7.0,8)";resolution:=optional,
org.eclipse.jetty.security;bundle-version="[7.0,8)";resolution:=optional,
org.eclipse.jetty.server;bundle-version="[7.0,8)",
org.eclipse.jetty.servlet;bundle-version="[7.0,8)",
org.eclipse.jetty.servlets;bundle-version="[7.0,8)";resolution:=optional,
org.eclipse.jetty.util;bundle-version="[7.0,8)",
org.eclipse.jetty.webapp;bundle-version="[7.0,8)",
org.eclipse.jetty.xml;bundle-version="[7.0,8)"
Export-Package: org.eclipse.jetty.osgi.boot,
org.eclipse.jetty.osgi.boot.utils
Bundle-ActivationPolicy: lazy

View File

@ -0,0 +1,15 @@
source.. = src/main/java/
output.. = target/classes/
bin.includes = META-INF/,\
.,\
jettyhome/
bin.excludes = jettyhome/logs/2009_09_21.request.log,\
jettyhome/lib/atomikos-util-3.5.8.jar,\
jettyhome/lib/transactions-3.5.8.jar,\
jettyhome/lib/transactions-api-3.5.8.jar,\
jettyhome/lib/transactions-jdbc-3.5.8.jar,\
jettyhome/lib/transactions-jta-3.5.8.jar,\
jettyhome/lib/ext/derby-10.4.1.3.jar,\
jettyhome/lib/ext/derbytools-10.4.1.3.jar
src.includes = META-INF/,\
jettyhome/

View File

@ -0,0 +1,2 @@
Default locations for standard context definitions.
Those applications are unlikely to have access to the OSGi framework currently.

View File

@ -0,0 +1,2 @@
This folder contains the default jetty configurations file for the server.
In production, it is likely to be a different folder outside of the jetty's bootstrap plugin.

View File

@ -0,0 +1,72 @@
#
# This is a sample properties file for the org.mortbay.jetty.security.JDBCUserRealm
# implemtation of the UserRealm interface. This allows Jetty users authentication
# to work from a database.
#
# +-------+ +------------+ +-------+
# | users | | user_roles | | roles |
# +-------+ +------------+ +-------+
# | id | /| user_id |\ | id |
# | user -------| role_id |------- role |
# | pwd | \| |/ | |
# +-------+ +------------+ +-------+
#
#
# 'cachetime' is a time in seconds to cache positive database
# lookups in internal hash table. Set to 0 to disable caching.
#
#
# For MySQL:
# create a MYSQL user called "jetty" with password "jetty"
#
# Create the tables:
# create table users
# (
# id integer primary key,
# username varchar(100) not null unique key,
# pwd varchar(20) not null
# );
#
# create table roles
# (
# id integer primary key,
# role varchar(100) not null unique key
# );
#
# create table user_roles
# (
# user_id integer not null,
# role_id integer not null,
# unique key (user_id, role_id),
# index(user_id)
# );
#
# I'm not sure unique key with a first component of user_id will be
# user by MySQL in query, so additional index wouldn't hurt.
#
# To test JDBC implementation:
#
# mysql> insert into users values (1, 'admin', 'password');
# mysql> insert into roles values (1, 'server-administrator');
# mysql> insert into roles values (2, 'content-administrator');
# mysql> insert into user_roles values (1, 1);
# mysql> insert into user_roles values (1, 2);
#
# Replace HashUserRealm in etc/admin.xml with JDBCUserRealm and
# set path to properties file.
#
jdbcdriver = org.gjt.mm.mysql.Driver
url = jdbc:mysql://localhost/jetty
username = jetty
password = jetty
usertable = users
usertablekey = id
usertableuserfield = username
usertablepasswordfield = pwd
roletable = roles
roletablekey = id
roletablerolefield = role
userroletable = user_roles
userroletableuserkey = user_id
userroletablerolekey = role_id
cachetime = 300

View File

@ -0,0 +1,18 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure id="Server" class="org.mortbay.jetty.Server">
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- Add a AJP listener on port 8009 -->
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<Call name="addConnector">
<Arg>
<New class="org.mortbay.jetty.ajp.Ajp13SocketConnector">
<Set name="port">8009</Set>
</New>
</Arg>
</Call>
</Configure>

View File

@ -0,0 +1,23 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<!-- =============================================================== -->
<!-- Mixin configuration for Block socket connector -->
<!-- -->
<!-- =============================================================== -->
<Configure id="Server" class="org.mortbay.jetty.Server">
<!-- Use this connector if NIO is not available. -->
<Call name="addConnector">
<Arg>
<New class="org.mortbay.jetty.bio.SocketConnector">
<Set name="port"><SystemProperty name="jetty.bio.port" default="8081"/></Set>
<Set name="maxIdleTime">50000</Set>
<Set name="lowResourceMaxIdleTime">1500</Set>
</New>
</Arg>
</Call>
</Configure>

View File

@ -0,0 +1,35 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure id="Server" class="org.mortbay.jetty.Server">
<!-- ======================================================== -->
<!-- java.security.auth.login.config System property -->
<!-- This is usually a runtime parameter to the jvm, but -->
<!-- it is placed here for convenience. -->
<!-- ======================================================== -->
<Call class="java.lang.System" name="setProperty">
<Arg>java.security.auth.login.config</Arg>
<Arg><SystemProperty name="jetty.home" default="." />/etc/login.conf</Arg>
</Call>
<!-- ======================================================== -->
<!-- An example JAAS realm setup -->
<!-- For more information see the jetty wiki at -->
<!-- http://http://docs.codehaus.org/display/JETTY/JAAS -->
<!-- ======================================================== -->
<Set name="UserRealms">
<Array type="org.mortbay.jetty.security.UserRealm">
<Item>
<New class="org.mortbay.jetty.plus.jaas.JAASUserRealm">
<Set name="Name">Test JAAS Realm</Set>
<Set name="LoginModuleName">xyz</Set>
</New>
</Item>
</Array>
</Set>
</Configure>

View File

@ -0,0 +1,54 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<!-- =============================================================== -->
<!-- Configure the JVM JMX Server -->
<!-- this configuration file should be used in combination with -->
<!-- other configuration files. e.g. -->
<!-- java -jar start.jar etc/jetty-jmx.xml etc/jetty.xml -->
<!-- See jetty-jmx-mx4j.xml for a non JVM server solution -->
<!-- =============================================================== -->
<Configure id="Server" class="org.mortbay.jetty.Server">
<!-- =========================================================== -->
<!-- Initialize an mbean server -->
<!-- =========================================================== -->
<!-- Use the jdk 1.5 platformMBeanServer -->
<Call id="MBeanServer" class="java.lang.management.ManagementFactory" name="getPlatformMBeanServer"/>
<!-- Use an mx4j mbean server - use this if running with jdk<1.5
<Call id="MBeanServer" class="javax.management.MBeanServerFactory" name="createMBeanServer"/>
-->
<!-- =========================================================== -->
<!-- Initialize the Jetty MBean container -->
<!-- =========================================================== -->
<Get id="Container" name="container">
<Call name="addEventListener">
<Arg>
<New class="org.mortbay.management.MBeanContainer">
<Arg><Ref id="MBeanServer"/></Arg>
<!-- If using < jdk1.5 uncomment to start http adaptor -->
<!-- Set name="managementPort">8082</Set -->
<Call name="start" />
</New>
</Arg>
</Call>
</Get>
<!-- optionally add a remote JMX connector
<Call id="jmxConnector" class="javax.management.remote.JMXConnectorServerFactory" name="newJMXConnectorServer">
<Arg>
<New class="javax.management.remote.JMXServiceURL">
<Arg>service:jmx:rmi:///jndi/rmi:///jettymbeanserver</Arg>
</New>
</Arg>
<Arg/>
<Arg><Ref id="MBeanServer"/></Arg>
<Call name="start"/>
</Call>
-->
</Configure>

View File

@ -0,0 +1,32 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<!-- =============================================================== -->
<!-- Configure stderr and stdout to a Jetty rollover log file -->
<!-- this configuration file should be used in combination with -->
<!-- other configuration files. e.g. -->
<!-- java -jar start.jar etc/jetty-logging.xml etc/jetty.xml -->
<!-- =============================================================== -->
<Configure id="Server" class="org.mortbay.jetty.Server">
<New id="ServerLog" class="java.io.PrintStream">
<Arg>
<New class="org.mortbay.util.RolloverFileOutputStream">
<Arg><SystemProperty name="jetty.home" default="."/>/logs/yyyy_mm_dd.stderrout.log</Arg>
<Arg type="boolean">false</Arg>
<Arg type="int">90</Arg>
<Arg><Call class="java.util.TimeZone" name="getTimeZone"><Arg>GMT</Arg></Call></Arg>
<Get id="ServerLogName" name="datedFilename"/>
</New>
</Arg>
</New>
<Call class="org.mortbay.log.Log" name="info"><Arg>Redirecting stderr/stdout to <Ref id="ServerLogName"/></Arg></Call>
<Call class="java.lang.System" name="setErr"><Arg><Ref id="ServerLog"/></Arg></Call>
<Call class="java.lang.System" name="setOut"><Arg><Ref id="ServerLog"/></Arg></Call>
</Configure>

View File

@ -0,0 +1,74 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<!-- =============================================================== -->
<!-- Configure Jetty Plus features -->
<!-- -->
<!-- This file sets up a WebAppDeployer to automatically deploy all -->
<!-- webapps in $jetty.home/webapps-plus at startup time, and to -->
<!-- enable all of them with Plus features (jndi etc). -->
<!-- -->
<!-- You can instead configure individual webapps with Jetty Plus -->
<!-- features by using the ContextDeployer (configured in -->
<!-- $jetty.home/etc/jetty.xml), and ensuring that you set the -->
<!-- same set of classes listed below in the "plusConfig" as the -->
<!-- webapp's configurationClasses. -->
<!-- -->
<!-- For more information about Jetty Plus, see the Jetty wiki at -->
<!-- http://docs.codehaus.org/display/JETTY/Jetty+Wiki -->
<!-- =============================================================== -->
<Configure id="Server" class="org.mortbay.jetty.Server">
<!-- =========================================================== -->
<!-- Example JAAS realm setup. -->
<!-- The LoginModuleName must be exactly the same as in the -->
<!-- login.conf file, and the realm Name must be the same as in -->
<!-- the web.xml file. -->
<!-- =========================================================== -->
<!--
<Call name="addUserRealm">
<Arg>
<New class="org.mortbay.jetty.plus.jaas.JAASUserRealm">
<Set name="name">xyzrealm</Set>
<Set name="LoginModuleName">xyz</Set>
</New>
</Arg>
</Call>
-->
<!-- =========================================================== -->
<!-- Configurations for WebAppContexts -->
<!-- Sequence of configurations to enable Plus features. -->
<!-- =========================================================== -->
<Array id="plusConfig" type="java.lang.String">
<Item>org.mortbay.jetty.webapp.WebInfConfiguration</Item>
<Item>org.mortbay.jetty.plus.webapp.EnvConfiguration</Item>
<Item>org.mortbay.jetty.plus.webapp.Configuration</Item>
<Item>org.mortbay.jetty.webapp.JettyWebXmlConfiguration</Item>
<Item>org.mortbay.jetty.webapp.TagLibConfiguration</Item>
</Array>
<!-- =========================================================== -->
<!-- Deploy all webapps in webapps-plus -->
<!-- =========================================================== -->
<!-- Uncomment the following to set up a WebAppDeployer that will -->
<!-- deploy webapps from a directory called webapps-plus. Note -->
<!-- that you will need to create this directory first! -->
<!--
<Call name="addLifeCycle">
<Arg>
<New class="org.mortbay.jetty.deployer.WebAppDeployer">
<Set name="contexts"><Ref id="Contexts"/></Set>
<Set name="webAppDir"><SystemProperty name="jetty.home" default="."/>/webapps-plus</Set>
<Set name="parentLoaderPriority">false</Set>
<Set name="extract">true</Set>
<Set name="allowDuplicates">false</Set>
<Set name="defaultsDescriptor"><SystemProperty name="jetty.home" default="."/>/etc/webdefault.xml</Set>
<Set name="configurationClasses"><Ref id="plusConfig"/></Set>
</New>
</Arg>
</Call>
-->
</Configure>

View File

@ -0,0 +1,149 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<!-- =============================================================== -->
<!-- Mixin the RewriteHandler -->
<!-- =============================================================== -->
<Configure id="Server" class="org.mortbay.jetty.Server">
<!-- =========================================================== -->
<!-- Configure Rewrite Handler -->
<!-- =========================================================== -->
<Get id="oldhandler" name="handler"/>
<Set name="handler">
<New id="Rewrite" class="org.mortbay.jetty.handler.rewrite.RewriteHandler">
<Set name="handler"><Ref id="oldhandler"/></Set>
<Set name="rewriteRequestURI">true</Set>
<Set name="rewritePathInfo">false</Set>
<Set name="originalPathAttribute">requestedPath</Set>
<Set name="rules">
<Array type="org.mortbay.jetty.handler.rewrite.Rule">
<!-- return an error message if low on threads; put this at the top so it will be processed first -->
<Item>
<New id="lowThreads" class="org.mortbay.jetty.handler.rewrite.LowThreadsRuleContainer">
<!-- set the trigger for low threads ridiculously low
uncomment the block below to see it in action -->
<!--Ref id="Server">
<Get id="serverThreadPool" name="threadPool">
<Set name="minThreads">3</Set>
<Set name="maxThreads">4</Set>
<Set name="lowThreads">0</Set>
</Get>
</Ref>
<Set name="threadPool"><Ref id="serverThreadPool"/></Set-->
<Call name="addRule">
<Arg>
<New id="busyresponse" class="org.mortbay.jetty.handler.rewrite.ResponsePatternRule">
<Set name="pattern">/*</Set>
<Set name="code">500</Set>
<Set name="reason">Server busy</Set>
</New>
</Arg>
</Call>
</New>
</Item>
<!-- Add rule to protect against IE ssl bug -->
<Item>
<New class="org.mortbay.jetty.handler.rewrite.MsieSslRule"/>
</Item>
<!-- protect favicon handling -->
<Item>
<New class="org.mortbay.jetty.handler.rewrite.HeaderPatternRule">
<Set name="pattern">/favicon.ico</Set>
<Set name="name">Cache-Control</Set>
<Set name="value">Max-Age=3600,public</Set>
<Set name="terminating">true</Set>
</New>
</Item>
<!-- add a regex rule -->
<Item>
<New class="org.mortbay.jetty.handler.rewrite.RewriteRegexRule">
<Set name="regex">/rewrite/dump/regex/([^/]*)/(.*)</Set>
<Set name="replacement">/test/dump/$2/$1</Set>
</New>
</Item>
<!-- add a rewrite rule -->
<Item>
<New id="" class="org.mortbay.jetty.handler.rewrite.RewritePatternRule">
<Set name="pattern">/rewrite</Set>
<Set name="replacement">/rewrittento</Set>
</New>
</Item>
<!-- add a response rule -->
<Item>
<New id="response" class="org.mortbay.jetty.handler.rewrite.ResponsePatternRule">
<Set name="pattern">/rewrite/session/</Set>
<Set name="code">401</Set>
<Set name="reason">Setting error code 401</Set>
</New>
</Item>
<!-- add a header pattern rule -->
<Item>
<New id="header" class="org.mortbay.jetty.handler.rewrite.HeaderPatternRule">
<Set name="pattern">*.jsp</Set>
<Set name="name">Server</Set>
<Set name="value">Server for JSP</Set>
</New>
</Item>
<!-- add a redirect -->
<Item>
<New id="redirect" class="org.mortbay.jetty.handler.rewrite.RedirectPatternRule">
<Set name="pattern">/rewrite/dispatch</Set>
<Set name="location">http://jetty.mortbay.org</Set>
</New>
</Item>
<Item>
<New id="forwardedHttps" class="org.mortbay.jetty.handler.rewrite.ForwardedSchemeHeaderRule">
<Set name="header">X-Forwarded-Scheme</Set>
<Set name="headerValue">https</Set>
<Set name="scheme">https</Set>
</New>
</Item>
<Item>
<New id="virtualHost" class="org.mortbay.jetty.handler.rewrite.VirtualHostRuleContainer">
<Set name="virtualHosts">
<Array type="java.lang.String">
<Item>mortbay.com</Item>
<Item>www.mortbay.com</Item>
<Item>mortbay.org</Item>
<Item>www.mortbay.org</Item>
</Array>
</Set>
<Call name="addRule">
<Arg>
<New class="org.mortbay.jetty.handler.rewrite.CookiePatternRule">
<Set name="pattern">/*</Set>
<Set name="name">CookiePatternRule</Set>
<Set name="value">1</Set>
</New>
</Arg>
</Call>
</New>
</Item>
</Array>
</Set>
</New>
</Set>
</Configure>

View File

@ -0,0 +1,17 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<!-- =============================================================== -->
<!-- Configure the Jetty SetUIDServer -->
<!-- this configuration file should be used in combination with -->
<!-- other configuration files. e.g. -->
<!-- java -jar start.jar etc/jetty-setuid.xml etc/jetty.xml -->
<!-- =============================================================== -->
<Configure id="Server" class="org.mortbay.setuid.SetUIDServer">
<Set name="startServerAsPrivileged">false</Set>
<Set name="umask">2</Set>
<Set name="uid">jetty</Set>
<Set name="gid">jetty</Set>
</Configure>

View File

@ -0,0 +1,35 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<!-- =============================================================== -->
<!-- Configure SSL for the Jetty Server -->
<!-- this configuration file should be used in combination with -->
<!-- other configuration files. e.g. -->
<!-- java -jar start.jar etc/jetty.xml etc/jetty-ssl.xml -->
<!-- =============================================================== -->
<Configure id="Server" class="org.mortbay.jetty.Server">
<Call name="addConnector">
<Arg>
<New class="org.mortbay.jetty.security.SslSocketConnector">
<Set name="Port">8443</Set>
<Set name="maxIdleTime">30000</Set>
<Set name="handshakeTimeout">2000</Set>
<Set name="keystore"><SystemProperty name="jetty.home" default="." />/etc/keystore</Set>
<Set name="password">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set>
<Set name="keyPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set>
<Set name="truststore"><SystemProperty name="jetty.home" default="." />/etc/keystore</Set>
<Set name="trustPassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set>
<Set name="handshakeTimeout">2000</Set>
<!-- Set name="ThreadPool">
<New class="org.mortbay.thread.BoundedThreadPool">
<Set name="minThreads">10</Set>
<Set name="maxThreads">250</Set>
</New>
</Set -->
</New>
</Arg>
</Call>
</Configure>

View File

@ -0,0 +1,25 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<!-- =============================================================== -->
<!-- Configure SSL for the Jetty Server -->
<!-- this configuration file should be used in combination with -->
<!-- other configuration files. e.g. -->
<!-- java -jar start.jar etc/jetty.xml etc/jetty-ssl.xml -->
<!-- =============================================================== -->
<Configure id="Server" class="org.mortbay.jetty.Server">
<Call name="addConnector">
<Arg>
<New class="org.mortbay.jetty.security.SslSelectChannelConnector">
<Set name="Port">8444</Set>
<Set name="maxIdleTime">30000</Set>
<Set name="Acceptors">2</Set>
<Set name="AcceptQueueSize">100</Set>
<Set name="Keystore"><SystemProperty name="jetty.home" default="." />/etc/keystore</Set>
<Set name="Password">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set>
<Set name="KeyPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set>
</New>
</Arg>
</Call>
</Configure>

View File

@ -0,0 +1,19 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<!-- =============================================================== -->
<!-- Mixin the Statistics Handler -->
<!-- =============================================================== -->
<Configure id="Server" class="org.mortbay.jetty.Server">
<Get id="oldhandler" name="handler"/>
<Set name="handler">
<New id="StatsHandler" class="org.mortbay.jetty.handler.AtomicStatisticsHandler">
<!-- Use non-atomic for jdk 1.4 -->
<!-- New id="StatsHandler" class="org.mortbay.jetty.handler.StatisticsHandler" -->
<Set name="handler"><Ref id="oldhandler"/></Set>
</New>
</Set>
</Configure>

View File

@ -0,0 +1,28 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<!-- =============================================================== -->
<!-- Configure the Jetty Server -->
<!-- -->
<!-- Documentation of this file format can be found at: -->
<!-- http://docs.codehaus.org/display/JETTY/jetty.xml -->
<!-- -->
<!-- =============================================================== -->
<Configure id="Server" class="org.mortbay.jetty.Server">
<Call name="addLifeCycle">
<Arg>
<New class="org.mortbay.jetty.win32service.Win32Service">
<Set name="server"><Ref id="Server"/></Set>
</New>
</Arg>
</Call>
<Set name="stopAtShutdown">true</Set>
<!-- ensure/prevent Server: header being sent to browsers -->
<Set name="sendServerVersion">true</Set>
</Configure>

View File

@ -0,0 +1,56 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<!-- =============================================================== -->
<!-- Configuration for starting up Jetty using inetd/xinetd -->
<!-- This feature requires at least Java 5 -->
<!-- -->
<!-- Making it a mixin for convenience, but note that if used -->
<!-- with jetty.xml, Jetty will use multiple connectors -->
<!-- =============================================================== -->
<!-- Sample xinetd configuration (restart xinetd after adding the configuration file)
service jetty
{
disable = no
id = jetty
type = UNLISTED
wait = yes
socket_type = stream
# change this
user = username
group = groupname
port = 2001
# sample script for running jetty as a service
# replace $JETTY_HOME with /path/to/jetty_home/
server = $JETTY_HOME/bin/jetty-xinetd.sh
}
-->
<Configure id="Server" class="org.mortbay.jetty.Server">
<Call name="addConnector">
<Arg>
<!-- Inherited channel (from inetd/xinetd) -->
<New class="org.mortbay.jetty.nio.InheritedChannelConnector">
<!-- Optional. Fallback in case System.inheritedChannel() does not give a ServerSocketChannel
<Set name="port"><SystemProperty name="jetty.service.port" default="8082"/></Set>
-->
<!-- sane defaults -->
<Set name="maxIdleTime">300000</Set>
<Set name="Acceptors">2</Set>
<Set name="statsOn">false</Set>
<Set name="lowResourcesConnections">20000</Set>
<Set name="lowResourcesMaxIdleTime">5000</Set>
</New>
</Arg>
</Call>
</Configure>

View File

@ -0,0 +1,209 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<!-- =============================================================== -->
<!-- Configure the Jetty Server -->
<!-- -->
<!-- Documentation of this file format can be found at: -->
<!-- http://docs.codehaus.org/display/JETTY/jetty.xml -->
<!-- -->
<!-- =============================================================== -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- =========================================================== -->
<!-- Server Thread Pool -->
<!-- =========================================================== -->
<Set name="ThreadPool">
<!-- Default queued blocking threadpool
-->
<New class="org.eclipse.jetty.util.thread.QueuedThreadPool">
<Set name="minThreads">10</Set>
<Set name="maxThreads">200</Set>
</New>
<!-- Optional Java 5 bounded threadpool with job queue
<New class="org.eclipse.thread.concurrent.ThreadPool">
<Set name="corePoolSize">50</Set>
<Set name="maximumPoolSize">50</Set>
</New>
-->
</Set>
<!-- Added from jetty-plus.xml but is this really necessary? -->
<!-- =========================================================== -->
<!-- Configurations for WebAppContexts -->
<!-- Sequence of configurations to enable Plus features. -->
<!-- =========================================================== -->
<Array id="plusConfig" type="java.lang.String">
<Item>org.mortbay.jetty.webapp.WebInfConfiguration</Item>
<Item>org.mortbay.jetty.plus.webapp.EnvConfiguration</Item>
<Item>org.mortbay.jetty.plus.webapp.Configuration</Item>
<Item>org.mortbay.jetty.webapp.JettyWebXmlConfiguration</Item>
<Item>org.mortbay.jetty.webapp.TagLibConfiguration</Item>
</Array>
<!-- =========================================================== -->
<!-- Set connectors -->
<!-- =========================================================== -->
<Call name="addConnector">
<Arg>
<New class="org.eclipse.jetty.server.nio.SelectChannelConnector">
<Set name="host"><SystemProperty name="jetty.host" /></Set>
<Set name="port"><SystemProperty name="jetty.port" default="8080"/></Set>
<Set name="maxIdleTime">300000</Set>
<Set name="Acceptors">2</Set>
<Set name="statsOn">false</Set>
<Set name="confidentialPort">8443</Set>
<Set name="lowResourcesConnections">20000</Set>
<Set name="lowResourcesMaxIdleTime">5000</Set>
</New>
</Arg>
</Call>
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- To add a HTTPS SSL connector -->
<!-- mixin jetty-ssl.xml: -->
<!-- java -jar start.jar etc/jetty.xml etc/jetty-ssl.xml -->
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- To add a HTTP blocking connector -->
<!-- mixin jetty-bio.xml: -->
<!-- java -jar start.jar etc/jetty.xml etc/jetty-bio.xml -->
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- To allow Jetty to be started from xinetd -->
<!-- mixin jetty-xinetd.xml: -->
<!-- java -jar start.jar etc/jetty.xml etc/jetty-xinetd.xml -->
<!-- -->
<!-- See jetty-xinetd.xml for further instructions. -->
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- =========================================================== -->
<!-- Set handler Collection Structure -->
<!-- =========================================================== -->
<Set name="handler">
<New id="Handlers" class="org.eclipse.jetty.server.handler.HandlerCollection">
<Set name="handlers">
<Array type="org.eclipse.jetty.server.Handler">
<Item>
<New id="Contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection"/>
</Item>
<Item>
<New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/>
</Item>
<Item>
<New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler"/>
</Item>
</Array>
</Set>
</New>
</Set>
<!-- =========================================================== -->
<!-- Configure the context deployer -->
<!-- A context deployer will deploy contexts described in -->
<!-- configuration files discovered in a directory. -->
<!-- The configuration directory can be scanned for hot -->
<!-- deployments at the configured scanInterval. -->
<!-- -->
<!-- This deployer is configured to deploy contexts configured -->
<!-- in the $JETTY_HOME/contexts directory -->
<!-- -->
<!-- =========================================================== -->
<Call name="addBean">
<Arg>
<New class="org.eclipse.jetty.deploy.ContextDeployer">
<Set name="contexts"><Ref id="Contexts"/></Set>
<Set name="configurationDir"><SystemProperty name="jetty.home" default="."/>/contexts</Set>
<Set name="scanInterval">5</Set>
<Call name="setAttribute">
<Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
<Arg>.*/jsp-api-[^/]*\.jar$|.*/jsp-[^/]*\.jar$</Arg>
</Call>
</New>
</Arg>
</Call>
<!-- =========================================================== -->
<!-- Configure the webapp deployer. -->
<!-- A webapp deployer will deploy standard webapps discovered -->
<!-- in a directory at startup, without the need for additional -->
<!-- configuration files. It does not support hot deploy or -->
<!-- non standard contexts (see ContextDeployer above). -->
<!-- -->
<!-- This deployer is configured to deploy webapps from the -->
<!-- $JETTY_HOME/webapps directory -->
<!-- -->
<!-- Normally only one type of deployer need be used. -->
<!-- -->
<!-- =========================================================== -->
<Call name="addBean">
<Arg>
<New class="org.eclipse.jetty.deploy.WebAppDeployer">
<Set name="contexts"><Ref id="Contexts"/></Set>
<Set name="webAppDir"><SystemProperty name="jetty.home" default="."/>/webapps</Set>
<Set name="parentLoaderPriority">false</Set>
<Set name="extract">true</Set>
<Set name="allowDuplicates">false</Set>
<Set name="defaultsDescriptor"><SystemProperty name="jetty.home" default="."/>/etc/webdefault.xml</Set>
<Call name="setAttribute">
<Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
<Arg>.*/jsp-api-[^/]*\.jar$|.*/jsp-[^/]*\.jar$</Arg>
</Call>
</New>
</Arg>
</Call>
<!-- =========================================================== -->
<!-- Configure Authentication Login Service -->
<!-- Realms may be configured for the entire server here, or -->
<!-- they can be configured for a specific web app in a context -->
<!-- configuration (see $(jetty.home)/contexts/test.xml for an -->
<!-- example). -->
<!-- =========================================================== -->
<Call name="addBean">
<Arg>
<New class="org.eclipse.jetty.security.HashLoginService">
<Set name="name">Test Realm</Set>
<Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
<Set name="refreshInterval">0</Set>
</New>
</Arg>
</Call>
<!-- =========================================================== -->
<!-- Configure Request Log -->
<!-- Request logs may be configured for the entire server here, -->
<!-- or they can be configured for a specific web app in a -->
<!-- contexts configuration (see $(jetty.home)/contexts/test.xml -->
<!-- for an example). -->
<!-- =========================================================== -->
<Ref id="RequestLog">
<Set name="requestLog">
<New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog">
<Set name="filename"><SystemProperty name="jetty.home" default="."/>/logs/yyyy_mm_dd.request.log</Set>
<Set name="filenameDateFormat">yyyy_MM_dd</Set>
<Set name="retainDays">90</Set>
<Set name="append">true</Set>
<Set name="extended">false</Set>
<Set name="logCookies">false</Set>
<Set name="LogTimeZone">GMT</Set>
</New>
</Set>
</Ref>
<!-- =========================================================== -->
<!-- extra options -->
<!-- =========================================================== -->
<Set name="stopAtShutdown">true</Set>
<Set name="sendServerVersion">true</Set>
<Set name="sendDateHeader">true</Set>
<Set name="gracefulShutdown">1000</Set>
</Configure>

View File

@ -0,0 +1,5 @@
xyz {
org.mortbay.jetty.plus.jaas.spi.PropertyFileLoginModule required
debug="true"
file="${jetty.home}/etc/login.properties";
};

View File

@ -0,0 +1 @@
me=me,me,roleA

View File

@ -0,0 +1,21 @@
#
# This file defines users passwords and roles for a HashUserRealm
#
# The format is
# <username>: <password>[,<rolename> ...]
#
# Passwords may be clear text, obfuscated or checksummed. The class
# org.mortbay.util.Password should be used to generate obfuscated
# passwords or password checksums
#
# If DIGEST Authentication is used, the password must be in a recoverable
# format, either plain text or OBF:.
#
jetty: MD5:164c88b302622e17050af52c89945d44,user
admin: CRYPT:ad1ks..kc.1Ug,server-administrator,content-administrator,admin
other: OBF:1xmk1w261u9r1w1c1xmq
plain: plain
user: password
# This entry is for digest auth. The credential is a MD5 hash of username:realmname:password
digest: MD5:6e120743ad67abfbc385bc2bb754e297

View File

@ -0,0 +1,404 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- ===================================================================== -->
<!-- This file contains the default descriptor for web applications. -->
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- The intent of this descriptor is to include jetty specific or common -->
<!-- configuration for all webapps. If a context has a webdefault.xml -->
<!-- descriptor, it is applied before the contexts own web.xml file -->
<!-- -->
<!-- A context may be assigned a default descriptor by: -->
<!-- + Calling WebApplicationContext.setDefaultsDescriptor -->
<!-- + Passed an arg to addWebApplications -->
<!-- -->
<!-- This file is used both as the resource within the jetty.jar (which is -->
<!-- used as the default if no explicit defaults descriptor is set) and it -->
<!-- is copied to the etc directory of the Jetty distro and explicitly -->
<!-- by the jetty.xml file. -->
<!-- -->
<!-- ===================================================================== -->
<web-app
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
metadata-complete="true"
version="2.5">
<description>
Default web.xml file.
This file is applied to a Web application before it's own WEB_INF/web.xml file
</description>
<!-- ==================================================================== -->
<!-- Context params to control Session Cookies -->
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- UNCOMMENT TO ACTIVATE
<context-param>
<param-name>org.eclipse.jetty.servlet.SessionDomain</param-name>
<param-value>127.0.0.1</param-value>
</context-param>
<context-param>
<param-name>org.eclipse.jetty.servlet.SessionPath</param-name>
<param-value>/</param-value>
</context-param>
<context-param>
<param-name>org.eclipse.jetty.servlet.MaxAge</param-name>
<param-value>-1</param-value>
</context-param>
-->
<!-- ==================================================================== -->
<!-- The default servlet. -->
<!-- This servlet, normally mapped to /, provides the handling for static -->
<!-- content, OPTIONS and TRACE methods for the context. -->
<!-- The following initParameters are supported: -->
<!-- -->
<!-- acceptRanges If true, range requests and responses are -->
<!-- supported -->
<!-- -->
<!-- dirAllowed If true, directory listings are returned if no -->
<!-- welcome file is found. Else 403 Forbidden. -->
<!-- -->
<!-- welcomeServlets If true, attempt to dispatch to welcome files -->
<!-- that are servlets, if no matching static -->
<!-- resources can be found. -->
<!-- -->
<!-- redirectWelcome If true, redirect welcome file requests -->
<!-- else use request dispatcher forwards -->
<!-- -->
<!-- gzip If set to true, then static content will be served-->
<!-- as gzip content encoded if a matching resource is -->
<!-- found ending with ".gz" -->
<!-- -->
<!-- resoureBase Can be set to replace the context resource base -->
<!-- -->
<!-- relativeResourceBase -->
<!-- Set with a pathname relative to the base of the -->
<!-- servlet context root. Useful for only serving -->
<!-- static content from only specific subdirectories. -->
<!-- -->
<!-- useFileMappedBuffer -->
<!-- If set to true (the default), a memory mapped -->
<!-- file buffer will be used to serve static content -->
<!-- when using an NIO connector. Setting this value -->
<!-- to false means that a direct buffer will be used -->
<!-- instead. If you are having trouble with Windows -->
<!-- file locking, set this to false. -->
<!-- -->
<!-- cacheControl If set, all static content will have this value -->
<!-- set as the cache-control header. -->
<!-- -->
<!-- maxCacheSize Maximum size of the static resource cache -->
<!-- -->
<!-- maxCachedFileSize Maximum size of any single file in the cache -->
<!-- -->
<!-- maxCachedFiles Maximum number of files in the cache -->
<!-- -->
<!-- cacheType "nio", "bio" or "both" to determine the type(s) -->
<!-- of resource cache. A bio cached buffer may be used-->
<!-- by nio but is not as efficient as a nio buffer. -->
<!-- An nio cached buffer may not be used by bio. -->
<!-- -->
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class>
<init-param>
<param-name>acceptRanges</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>dirAllowed</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>welcomeServlets</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>redirectWelcome</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>maxCacheSize</param-name>
<param-value>256000000</param-value>
</init-param>
<init-param>
<param-name>maxCachedFileSize</param-name>
<param-value>10000000</param-value>
</init-param>
<init-param>
<param-name>maxCachedFiles</param-name>
<param-value>1000</param-value>
</init-param>
<init-param>
<param-name>cacheType</param-name>
<param-value>both</param-value>
</init-param>
<init-param>
<param-name>gzip</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>useFileMappedBuffer</param-name>
<param-value>true</param-value>
</init-param>
<!--
<init-param>
<param-name>cacheControl</param-name>
<param-value>max-age=3600,public</param-value>
</init-param>
-->
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
<!-- ==================================================================== -->
<!-- JSP Servlet -->
<!-- This is the jasper JSP servlet from the jakarta project -->
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- The JSP page compiler and execution servlet, which is the mechanism -->
<!-- used by Glassfish to support JSP pages. Traditionally, this servlet -->
<!-- is mapped to URL patterh "*.jsp". This servlet supports the -->
<!-- following initialization parameters (default values are in square -->
<!-- brackets): -->
<!-- -->
<!-- checkInterval If development is false and reloading is true, -->
<!-- background compiles are enabled. checkInterval -->
<!-- is the time in seconds between checks to see -->
<!-- if a JSP page needs to be recompiled. [300] -->
<!-- -->
<!-- compiler Which compiler Ant should use to compile JSP -->
<!-- pages. See the Ant documenation for more -->
<!-- information. [javac] -->
<!-- -->
<!-- classdebuginfo Should the class file be compiled with -->
<!-- debugging information? [true] -->
<!-- -->
<!-- classpath What class path should I use while compiling -->
<!-- generated servlets? [Created dynamically -->
<!-- based on the current web application] -->
<!-- Set to ? to make the container explicitly set -->
<!-- this parameter. -->
<!-- -->
<!-- development Is Jasper used in development mode (will check -->
<!-- for JSP modification on every access)? [true] -->
<!-- -->
<!-- enablePooling Determines whether tag handler pooling is -->
<!-- enabled [true] -->
<!-- -->
<!-- fork Tell Ant to fork compiles of JSP pages so that -->
<!-- a separate JVM is used for JSP page compiles -->
<!-- from the one Tomcat is running in. [true] -->
<!-- -->
<!-- ieClassId The class-id value to be sent to Internet -->
<!-- Explorer when using <jsp:plugin> tags. -->
<!-- [clsid:8AD9C840-044E-11D1-B3E9-00805F499D93] -->
<!-- -->
<!-- javaEncoding Java file encoding to use for generating java -->
<!-- source files. [UTF-8] -->
<!-- -->
<!-- keepgenerated Should we keep the generated Java source code -->
<!-- for each page instead of deleting it? [true] -->
<!-- -->
<!-- logVerbosityLevel The level of detailed messages to be produced -->
<!-- by this servlet. Increasing levels cause the -->
<!-- generation of more messages. Valid values are -->
<!-- FATAL, ERROR, WARNING, INFORMATION, and DEBUG. -->
<!-- [WARNING] -->
<!-- -->
<!-- mappedfile Should we generate static content with one -->
<!-- print statement per input line, to ease -->
<!-- debugging? [false] -->
<!-- -->
<!-- -->
<!-- reloading Should Jasper check for modified JSPs? [true] -->
<!-- -->
<!-- suppressSmap Should the generation of SMAP info for JSR45 -->
<!-- debugging be suppressed? [false] -->
<!-- -->
<!-- dumpSmap Should the SMAP info for JSR45 debugging be -->
<!-- dumped to a file? [false] -->
<!-- False if suppressSmap is true -->
<!-- -->
<!-- scratchdir What scratch directory should we use when -->
<!-- compiling JSP pages? [default work directory -->
<!-- for the current web application] -->
<!-- -->
<!-- tagpoolMaxSize The maximum tag handler pool size [5] -->
<!-- -->
<!-- xpoweredBy Determines whether X-Powered-By response -->
<!-- header is added by generated servlet [false] -->
<!-- -->
<!-- If you wish to use Jikes to compile JSP pages: -->
<!-- Set the init parameter "compiler" to "jikes". Define -->
<!-- the property "-Dbuild.compiler.emacs=true" when starting Jetty -->
<!-- to cause Jikes to emit error messages in a format compatible with -->
<!-- Jasper. -->
<!-- If you get an error reporting that jikes can't use UTF-8 encoding, -->
<!-- try setting the init parameter "javaEncoding" to "ISO-8859-1". -->
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<servlet id="jsp">
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>logVerbosityLevel</param-name>
<param-value>DEBUG</param-value>
</init-param>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<!--
<init-param>
<param-name>classpath</param-name>
<param-value>?</param-value>
</init-param>
-->
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.jspf</url-pattern>
<url-pattern>*.jspx</url-pattern>
<url-pattern>*.xsp</url-pattern>
<url-pattern>*.JSP</url-pattern>
<url-pattern>*.JSPF</url-pattern>
<url-pattern>*.JSPX</url-pattern>
<url-pattern>*.XSP</url-pattern>
</servlet-mapping>
<!-- ==================================================================== -->
<!-- Dynamic Servlet Invoker. -->
<!-- This servlet invokes anonymous servlets that have not been defined -->
<!-- in the web.xml or by other means. The first element of the pathInfo -->
<!-- of a request passed to the envoker is treated as a servlet name for -->
<!-- an existing servlet, or as a class name of a new servlet. -->
<!-- This servlet is normally mapped to /servlet/* -->
<!-- This servlet support the following initParams: -->
<!-- -->
<!-- nonContextServlets If false, the invoker can only load -->
<!-- servlets from the contexts classloader. -->
<!-- This is false by default and setting this -->
<!-- to true may have security implications. -->
<!-- -->
<!-- verbose If true, log dynamic loads -->
<!-- -->
<!-- * All other parameters are copied to the -->
<!-- each dynamic servlet as init parameters -->
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- Uncomment for dynamic invocation
<servlet>
<servlet-name>invoker</servlet-name>
<servlet-class>org.eclipse.jetty.servlet.Invoker</servlet-class>
<init-param>
<param-name>verbose</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>nonContextServlets</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>dynamicParam</param-name>
<param-value>anyValue</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping> <servlet-name>invoker</servlet-name> <url-pattern>/servlet/*</url-pattern> </servlet-mapping>
-->
<!-- ==================================================================== -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<!-- ==================================================================== -->
<!-- Default MIME mappings -->
<!-- The default MIME mappings are provided by the mime.properties -->
<!-- resource in the org.eclipse.jetty.server.jar file. Additional or modified -->
<!-- mappings may be specified here -->
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- UNCOMMENT TO ACTIVATE
<mime-mapping>
<extension>mysuffix</extension>
<mime-type>mymime/type</mime-type>
</mime-mapping>
-->
<!-- ==================================================================== -->
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- ==================================================================== -->
<locale-encoding-mapping-list>
<locale-encoding-mapping><locale>ar</locale><encoding>ISO-8859-6</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>be</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>bg</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>ca</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>cs</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>da</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>de</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>el</locale><encoding>ISO-8859-7</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>en</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>es</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>et</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>fi</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>fr</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>hr</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>hu</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>is</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>it</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>iw</locale><encoding>ISO-8859-8</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>ja</locale><encoding>Shift_JIS</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>ko</locale><encoding>EUC-KR</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>lt</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>lv</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>mk</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>nl</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>no</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>pl</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>pt</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>ro</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>ru</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>sh</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>sk</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>sl</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>sq</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>sr</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>sv</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>tr</locale><encoding>ISO-8859-9</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>uk</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>zh</locale><encoding>GB2312</encoding></locale-encoding-mapping>
<locale-encoding-mapping><locale>zh_TW</locale><encoding>Big5</encoding></locale-encoding-mapping>
</locale-encoding-mapping-list>
<security-constraint>
<web-resource-collection>
<web-resource-name>Disable TRACE</web-resource-name>
<url-pattern>/</url-pattern>
<http-method>TRACE</http-method>
</web-resource-collection>
<auth-constraint/>
</security-constraint>
</web-app>

View File

@ -0,0 +1,2 @@
Place here the jars that are inserted in the jetty classloader.
As similar as possible as what this folder was for in the classical jetty installation.

View File

@ -0,0 +1,3 @@
This folder contains the logs by default during development time.
In production or outside the eclipse PDE, it is likely that a different jetty.home
was set or jetty.log so it won't be here.

View File

@ -0,0 +1,2 @@
This folder is part of the class-loader shared by the webapps run in jetty.
Typically it contains log4j configuration files.

View File

@ -0,0 +1,2 @@
Default locations for standard web-applications.
Those applications are unlikely to have access to the OSGi framework currently.

View File

@ -0,0 +1,182 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.boot;
import java.util.Properties;
import org.eclipse.jetty.osgi.boot.internal.webapp.JettyContextHandlerExtender;
import org.eclipse.jetty.osgi.boot.internal.webapp.JettyContextHandlerServiceTracker;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.webapp.WebAppContext;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
/**
* Experiment: bootstrap jetty's complete distrib from an OSGi bundle.
* Progress:
* <ol>
* <li> basic servlet [ok]</li>
* <li> basic jetty.xml [ok]</li>
* <li> basic jetty.xml and jetty-plus.xml [ok]</li>
* <li> basic jsp [ok with modifications]
* <ul>
* <li>Needed to modify the headers of jdt.core-3.1.1 so that its dependency on
* eclipse.runtime, eclipse.resources and eclipse.text are optional.
* Also we should depend on the latest jdt.core from eclipse-3.5 not from eclipse-3.1.1
* although that will require actual changes to jasper as some internal APIs of
* jdt.core have changed.</li>
* <li>Modifications to org.mortbay.jetty.jsp-2.1-glassfish:
* made all imports to ant, xalan and sun packages optional.</li>
* </ul>
* </li>
* <li> jsp with tag-libs [ok]</li>
* <li> test-jndi with atomikos and derby inside ${jetty.home}/lib/ext [ok]</li>
* </ul>
*/
public class JettyBootstrapActivator implements BundleActivator
{
private static JettyBootstrapActivator INSTANCE = null;
public static JettyBootstrapActivator getInstance()
{
return INSTANCE;
}
private ServiceRegistration _registeredServer;
private Server _server;
private JettyContextHandlerServiceTracker _jettyContextHandlerTracker;
/**
* Setup a new jetty Server, registers it as a service. Setup the Service
* tracker for the jetty ContextHandlers that are in charge of deploying the webapps.
* Setup the BundleListener that supports the extender pattern for the
* jetty ContextHandler.
*
* @param context
*/
public void start(BundleContext context) throws Exception
{
INSTANCE = this;
// todo: replace all this by the ManagedFactory so that we can start multiple jetty servers.
_server = new Server();
// expose the server as a service.
_registeredServer = context.registerService(_server.getClass().getName(),_server,new Properties());
// the tracker in charge of the actual deployment
// and that will configure and start the jetty server.
_jettyContextHandlerTracker = new JettyContextHandlerServiceTracker(context,_server);
// TODO: add a couple more checks on the properties?
// kind of nice not to so we can debug what is missing easily.
context.addServiceListener(_jettyContextHandlerTracker,"(objectclass=" + ContextHandler.class.getName() + ")");
// now ready to support the Extender pattern:
JettyContextHandlerExtender jettyContexHandlerExtender = new JettyContextHandlerExtender();
context.addBundleListener(jettyContexHandlerExtender);
jettyContexHandlerExtender.init(context);
}
/*
* (non-Javadoc)
*
* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception
{
try
{
if (_jettyContextHandlerTracker != null)
{
_jettyContextHandlerTracker.stop();
context.removeServiceListener(_jettyContextHandlerTracker);
}
if (_registeredServer != null)
{
try
{
_registeredServer.unregister();
_registeredServer = null;
}
catch (IllegalArgumentException ill)
{
// already unregistered.
}
}
}
finally
{
_server.stop();
INSTANCE = null;
}
}
/**
* Helper method that creates a new org.jetty.webapp.WebAppContext and
* registers it as an OSGi service. The tracker
* {@link JettyContextHandlerServiceTracker} will do the actual deployment.
*
* @param context
* The current bundle context
* @param webappFolderPath
* The path to the root of the webapp. Must be a path relative
* to bundle; either an absolute path.
* @param contextPath
* The context path. Must start with "/"
* @param classInBundle
* A class that belongs to the current bundle to inherit from the
* osgi classloader. Null to not have access to the OSGI classloader.
* @throws Exception
*/
public static void registerWebapplication(Bundle contributor,
String webappFolderPath, String contextPath) throws Exception
{
WebAppContext contextHandler = new WebAppContext();
Properties dic = new Properties();
dic.put("war",webappFolderPath);
dic.put("contextPath",contextPath);
contributor.getBundleContext().registerService(ContextHandler.class.getName(),contextHandler,dic);
}
/**
* Helper method that creates a new skeleton of a ContextHandler and registers it as an OSGi service.
* The tracker {@link JettyContextHandlerServiceTracker} will do the actual deployment.
*
* @param contributor
* The bundle that registers a new context
* @param contextFilePath
* The path to the file inside the bundle that defines the context.
* @throws Exception
*/
public static void registerContext(Bundle contributor, String contextFilePath) throws Exception
{
ContextHandler contextHandler = new ContextHandler();
Properties dic = new Properties();
dic.put("contextFilePath",contextFilePath);
contributor.getBundleContext().registerService(ContextHandler.class.getName(),contextHandler,dic);
}
public static void unregister(String contextPath)
{
// todo
}
}

View File

@ -0,0 +1,48 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.boot.internal.jsp;
import java.net.URL;
import java.net.URLClassLoader;
/**
* Tricky url classloader.
* In fact we don't want a real URLClassLoader: we want OSGi to provide its classloader
* and let it does.
* But to let {@link org.apache.jasper.compiler.TldLocationsCache} find the core tlds inside the jars
* we must be a URLClassLoader that returns an array of jars where tlds are stored
* when the method getURLs is called.
*/
public class TldLocatableURLClassloader extends URLClassLoader
{
private URL[] _jarsWithTldsInside;
public TldLocatableURLClassloader(ClassLoader osgiClassLoader, URL[] jarsWithTldsInside)
{
super(new URL[] {},osgiClassLoader);
_jarsWithTldsInside = jarsWithTldsInside;
}
/**
* @return the jars that contains tlds so that TldLocationsCache or
* TldScanner can find them.
*/
@Override
public URL[] getURLs()
{
return _jarsWithTldsInside;
}
}

View File

@ -0,0 +1,54 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.boot.internal.jsp;
import java.net.URL;
/**
* Add a classloader to the org.apache.jasper.compiler.TldLocatableURLClassloader.
* Hopefuly not necessary: still experimenting.
* @see TldLocatableURLClassloader
*/
public class TldLocatableURLClassloaderWithInsertedJettyClassloader extends TldLocatableURLClassloader
{
private ClassLoader _internalClassLoader;
public TldLocatableURLClassloaderWithInsertedJettyClassloader(ClassLoader osgiClassLoader,
ClassLoader internalClassLoader, URL[] jarsWithTldsInside)
{
super(osgiClassLoader,jarsWithTldsInside);
_internalClassLoader = internalClassLoader;
}
protected Class<?> findClass(String name) throws ClassNotFoundException
{
try
{
return super.findClass(name);
}
catch (ClassNotFoundException cne)
{
if (_internalClassLoader != null)
{
return _internalClassLoader.loadClass(name);
}
else
{
throw cne;
}
}
}
}

View File

@ -0,0 +1,115 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.boot.internal.serverfactory;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jetty.server.Server;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedServiceFactory;
/**
* This is a work in progress.
* <br/>
* In particular there is a lot of work required during the update of the configuration
* of a server. It might not be practical to in fact support that and re-deploy
* the webapps in the same state than before the server was stopped.
* <p>
* jetty servers are managed as OSGi services registered here.
* try to find out if a configuration will fail (ports already opened etc).
* </p>
* <p>
* Try to enable the creation and configuration of jetty servers in all the usual standard ways.
* The configuration of the server is defined by the properties passed to the service:
* <ol>
* <li>First look for jettyfactory. If the value is a jetty server, use that server</li>
* <li>Then look for jettyhome key. The value should be a java.io.File or a String that is a path to the folder
* It is required that a etc/jetty.xml file will be loated from that folder.</li>
* <li>Then look for a jettyxml key. The value should be a java.io.File or an InputStream
* that contains a jetty configuration file.</li>
* <li>TODO: More ways to configure a jetty server?
* (other IOCs like spring, equinox properties...)</li>
* <li>Throw an exception if none of the relevant parameters are found</li>
* </ol>
* </p>
*
* A nice intro to ManagedFactory in OSGi:
* http://www.osgilook.com/2009/08/04/factory-pattern-on-steroids-the-managedservicefactory/
*
* @author hmalphettes
*/
public class JettyServersManagedFactory implements ManagedServiceFactory {
/** key to configure the server according to a jetty home folder.
* the value is the corresponding java.io.File */
public static final String JETTY_HOME = "jettyhome";
/** key to configure the server according to a jetty.xml file */
public static final String JETTY_CONFIG_XML = "jettyxml";
/** invoke jetty-factory class. the value of this property is the
* instance of that class to call back. */
public static final String JETTY_FACTORY = "jettyfactory";
/** default property in jetty.xml that is used as the value of the http port. */
public static final String JETTY_HTTP_PORT = "jetty.http.port";
/** default property in jetty.xml that is used as the value of the https port. */
public static final String JETTY_HTTPS_PORT = "jetty.http.port";
/** */
private Map<String, Server> _servers = new HashMap<String, Server>();
/**
* @return the name for the factory
*/
public String getName()
{
return "Jetty Servers Managed Factory";
}
/**
* Called when the config for a jetty server is updated.
*/
public void updated(String pid, Dictionary properties)
throws ConfigurationException {
Server server = _servers.get(pid);
deleted(pid);
//do we need to collect the currently deployed http services and webapps
//to be able to re-deploy them later?
}
/**
* Will stop the corresponding server is there is one.
* @pid the unique identifier for that implementtion of the service: in this case the jetty server.
*/
public synchronized void deleted(String pid)
{
Server server = (Server) _servers.remove(pid);
if (server != null)
{
try
{
server.stop();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}

View File

@ -0,0 +1,161 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.boot.internal.webapp;
import java.net.URL;
import java.util.Dictionary;
import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;
/**
* Support bundles that declare the webapp directly through headers in their manifest.
* <p>
* Those headers will define a new WebApplication:
* <ul><li>Web-ContextPath</li>
* <li>Jetty-WarFolderPath</li>
* </ul>
* </p>
* <p>
* Those headers will define a new app started via a jetty-context:
* <ul><li>Jetty-ContextFilePath</li></ul>
* </p>
* And generate a jetty WebAppContext or another ContextHandler then registers it
* as service. Kind of simpler than declarative services and their xml files.
* Also avoid having the contributing bundle depend on jetty's package for WebApp.
*/
public class JettyContextHandlerExtender implements BundleListener {
/**
* Receives notification that a bundle has had a lifecycle change.
*
* @param event The <code>BundleEvent</code>.
*/
public void bundleChanged(BundleEvent event) {
switch (event.getType()) {
case BundleEvent.STARTED:
register(event.getBundle());
break;
case BundleEvent.STOPPING:
unregister(event.getBundle());
break;
}
}
/**
*
*/
public void init(BundleContext context) {
Bundle bundles[] = context.getBundles();
for (int i = 0; i < bundles.length; i++) {
if ((bundles[i].getState() & (Bundle.STARTING | Bundle.ACTIVE)) != 0) {
register(bundles[i]);
}
}
}
private void register(Bundle bundle) {
Dictionary<?, ?> dic = bundle.getHeaders();
String warFolderRelativePath = (String)dic.get("Jetty-WarFolderPath");
if (warFolderRelativePath != null) {
String contextPath = (String)dic.get("Web-ContextPath");
if (contextPath == null) {
contextPath = (String)dic.get("Jetty-WarContextPath");
}
if (contextPath == null || !contextPath.startsWith("/")) {
throw new IllegalArgumentException();
}
//create the corresponding service and publish it in the context of
//the contributor bundle.
try {
JettyBootstrapActivator.registerWebapplication(
bundle, warFolderRelativePath, contextPath);
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else if (dic.get("Jetty-ContextFilePath") != null) {
String contextFileRelativePath = (String)dic.get("Jetty-ContextFilePath");
if (contextFileRelativePath == null) {
//nothing to register here.
return;
}
//support for multiple webapps in the same bundle:
String[] pathes = contextFileRelativePath.split(",");
for (String path : pathes) {
try {
JettyBootstrapActivator.registerContext(
bundle, path.trim());
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} else {
//support for OSGi-RFC66; disclaimer, no access to the actual
//(draft) of the spec: just a couple of posts on the world-wide-web.
URL rfc66Webxml = bundle.getEntry("/WEB-INF/web.xml");
if (rfc66Webxml == null) {
return;//no webapp in here
}
//this is risky: should we make sure that there is no classes and jars directly available
//at the root of the of the bundle: otherwise they are accessible
//through the browser. we should enforce that the whole classpath is
//pointing to files and folders inside WEB-INF. We should filter-out
//META-INF too
String rfc66ContextPath = getWebContextPath(bundle, dic);
try {
JettyBootstrapActivator.registerWebapplication(bundle,
".", rfc66ContextPath);
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private String getWebContextPath(Bundle bundle, Dictionary<?, ?> dic) {
String rfc66ContextPath = (String)dic.get("Web-ContextPath");
if (rfc66ContextPath == null) {
//extract from the last token of the bundle's location:
//(really ?
//could consider processing the symbolic name as an alternative
//the location will often reflect the version.
//maybe this is relevant when the file is a war)
String location = bundle.getLocation();
String toks[] = location.replace('\\','/').split("/");
rfc66ContextPath = toks[toks.length-1];
//remove .jar, .war etc:
int lastDot = rfc66ContextPath.lastIndexOf('.');
if (lastDot != -1) {
rfc66ContextPath = rfc66ContextPath.substring(0, lastDot);
}
}
if (!rfc66ContextPath.startsWith("/")) {
rfc66ContextPath = "/" + rfc66ContextPath;
}
return rfc66ContextPath;
}
private void unregister(Bundle bundle) {
//nothing to do: when the bundle is stopped, each one of its service
//reference is also stopped and that is what we use to stop the corresponding
//webapps registered in that bundle.
}
}

View File

@ -0,0 +1,243 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.boot.internal.webapp;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.Scanner;
import org.eclipse.jetty.webapp.WebAppContext;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
/**
* When a {@link ContextHandler} service is activated we look into it and if
* the corresponding webapp is actually not configured then we go and register it.
* <p>
* The idea is to always go through this class when we deploy a new webapp
* on jetty.
* </p>
*/
public class JettyContextHandlerServiceTracker implements ServiceListener {
private final WebappRegistrationHelper _helper;
/** The context-handler to deactivate indexed by context handler */
private Map<ServiceReference, ContextHandler> _indexByServiceReference = new HashMap<ServiceReference, ContextHandler>();
/** The index is the bundle-symbolic-name/paht/to/context/file when there is such thing */
private Map<String, ServiceReference> _indexByContextFile = new HashMap<String, ServiceReference>();
/** or null when */
private String _osgiContextHomeFolderCanonicalPath;
/** in charge of detecting changes in the osgi contexts home folder. */
private Scanner _scanner;
/**
* @param context
* @param server
*/
public JettyContextHandlerServiceTracker(BundleContext context, Server server)
throws Exception {
_helper = new WebappRegistrationHelper(server);
_helper.setup(context, new HashMap<String, String>());
File contextHome = _helper.getOSGiContextsHome();
if (contextHome != null) {
_osgiContextHomeFolderCanonicalPath = contextHome.getCanonicalPath();
_scanner = new Scanner();
_scanner.setRecursive(true);
_scanner.setReportExistingFilesOnStartup(false);
_scanner.addListener(new Scanner.DiscreteListener() {
public void fileAdded(String filename) throws Exception {
//adding a file does not create a new app,
//it just reloads it with the new custom file.
//well, if the file does not define a context handler,
//then in fact it does remove it.
reloadJettyContextHandler(filename);
}
public void fileChanged(String filename) throws Exception {
reloadJettyContextHandler(filename);
}
public void fileRemoved(String filename) throws Exception {
//removing a file does not remove the app:
//it just goes back to the default embedded in the bundle.
//well, if there was no default then it does remove it.
reloadJettyContextHandler(filename);
}
});
}
}
public void stop() {
if (_scanner != null) {
_scanner.stop();
}
//the class that created the server is also in charge of stopping it.
//nothing to stop in the WebappRegistrationHelper
}
/**
* Receives notification that a service has had a lifecycle change.
*
* @param ev The <code>ServiceEvent</code> object.
*/
public void serviceChanged(ServiceEvent ev) {
ServiceReference sr = ev.getServiceReference();
switch(ev.getType()) {
case ServiceEvent.MODIFIED:
case ServiceEvent.UNREGISTERING: {
ContextHandler ctxtHandler = unregisterInIndex(ev.getServiceReference());
if (ctxtHandler != null && !ctxtHandler.isStopped()) {
try {
_helper.unregister(ctxtHandler);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
if (ev.getType() == ServiceEvent.UNREGISTERING) {
break;
} else {
//modified, meaning: we reload it. now that we stopped it; we can register it.
}
case ServiceEvent.REGISTERED: {
Bundle contributor = sr.getBundle();
BundleContext context = FrameworkUtil
.getBundle(JettyBootstrapActivator.class).getBundleContext();
ContextHandler contextHandler = (ContextHandler) context.getService(sr);
if (contextHandler.getServer() != null) {
//is configured elsewhere.
return;
}
if (contextHandler instanceof WebAppContext) {
WebAppContext webapp = (WebAppContext)contextHandler;
String contextPath = (String)sr.getProperty("contextPath");
if (contextPath == null) {
contextPath = webapp.getContextPath();
}
String war = (String)sr.getProperty("war");
try {
ContextHandler handler = _helper.registerWebapplication(contributor, war, contextPath);
if (handler != null) {
registerInIndex(handler, sr);
}
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
//consider this just an empty skeleton:
String contextFilePath = (String)sr.getProperty("contextFilePath");
if (contextFilePath == null) {
throw new IllegalArgumentException("the property contextFilePath is required");
}
try {
ContextHandler handler = _helper.registerContext(contributor, contextFilePath);
if (handler != null) {
registerInIndex(handler, sr);
}
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
break;
}
}
private void registerInIndex(ContextHandler handler, ServiceReference sr) {
_indexByServiceReference.put(sr, handler);
String key = getSymbolicNameAndContextFileKey(sr);
if (key != null) {
_indexByContextFile.put(key, sr);
}
}
/**
* Returns the ContextHandler to stop.
* @param reg
* @return the ContextHandler to stop.
*/
private ContextHandler unregisterInIndex(ServiceReference sr) {
ContextHandler handler = _indexByServiceReference.remove(sr);
String key = getSymbolicNameAndContextFileKey(sr);
if (key != null) {
_indexByContextFile.remove(key);
}
if (handler == null) {
//a warning?
return null;
}
return handler;
}
/**
* @param sr
* @return The key for a context file within the osgi contexts home folder.
*/
private String getSymbolicNameAndContextFileKey(ServiceReference sr) {
String contextFilePath = (String)sr.getProperty("contextFilePath");
if (contextFilePath != null) {
return sr.getBundle().getSymbolicName() + "/" + contextFilePath;
}
return null;
}
/**
* Called by the scanner when one of the context files is changed.
* @param contextFileFully
*/
void reloadJettyContextHandler(String canonicalNameOfFileChanged) {
String key = getNormalizedRelativePath(canonicalNameOfFileChanged);
if (key == null) {
return;
}
ServiceReference sr = _indexByContextFile.get(key);
if (sr == null) {
//nothing to do?
return;
}
serviceChanged(new ServiceEvent(ServiceEvent.MODIFIED, sr));
}
/**
* @param canFilename
* @return
*/
private String getNormalizedRelativePath(String canFilename) {
if (!canFilename.startsWith(_osgiContextHomeFolderCanonicalPath)) {
//why are we here: this does not look like a child of the osgi contexts home.
//warning?
return null;
}
return canFilename.substring(
_osgiContextHomeFolderCanonicalPath.length()).replace('\\', '/');
}
}

View File

@ -0,0 +1,216 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.boot.internal.webapp;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* <p>
* Magically extract the jettyhome folder from this bundle's jar place it somewhere
* in the file-system. Currently we do this only when we detect a system property
* 'jetty.magic.home.parent' or if we are inside the pde in dev mode.
* In dev mode we use the osgi.configuration.area folder.
* </p>
* <p>
*
* </p>
*/
class JettyHomeHelper {
/** only magically extract jettyhome if we are inside the pde. */
static boolean magic_install_only_in_pde = Boolean.valueOf(
System.getProperty("jetty.magic.home.pde.only", "true"));
/**
* Hack for eclipse-PDE.
* When no jetty.home was set, detect if we running inside eclipse-PDE
* in development mode.
* In that case extract the jettyhome folder embedded inside this plugin
* inside the configuration area folder. It is specific to the workspace.
* Set the folder as jetty.home.
* If the folder already exist don't extract it again.
* <p>
* If we are not pde dev mode, the same but look in the installation folder
* of eclipse itself.
* </p>
*
* @return
* @throws URISyntaxException
*/
static String setupJettyHomeInEclipsePDE(File thisbundlejar) {
File ecFolder = getParentFolderOfMagicHome();
if (ecFolder == null || !ecFolder.exists()) {
return null;
}
File jettyhome = new File(ecFolder, "jettyhome");
String path;
try {
path = jettyhome.getCanonicalPath();
if (jettyhome.exists()) {
System.setProperty("jetty.home", path);
return path;
} else {
//now grab the jar and unzip the relevant portion
unzipJettyHomeIntoDirectory(thisbundlejar, ecFolder);
System.setProperty("jetty.home", path);
return path;
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* @return true when we are currently being run by the pde in development mode.
*/
private static boolean isPDEDevelopment() {
String eclipseCommands = System.getProperty("eclipse.commands");
//detect if we are being run from the pde: ie during development.
return eclipseCommands != null && eclipseCommands.indexOf("-dev") != -1
&& (eclipseCommands.indexOf("-dev\n") != -1
|| eclipseCommands.indexOf("-dev\r") != -1
|| eclipseCommands.indexOf("-dev ") != -1);
}
// /**
// * @return
// */
// private static File getEclipseInstallationDir() {
// return getFile(System.getProperty("eclipse.home.location",
// System.getProperty("osgi.install.area")));
// }
/**
* @return
*/
private static File getConfigurationAreaDirectory() {
return getFile(System.getProperty("osgi.configuration.area"));
}
/**
* @param zipFile The current jar file for this bundle. contains an
* archive of the default jettyhome
* @param parentOfMagicJettyHome The folder inside which jettyhome is created.
*/
private static void unzipJettyHomeIntoDirectory(File thisbundlejar,
File parentOfMagicJettyHome) throws IOException {
ZipFile zipFile = null;
try {
zipFile = new ZipFile(thisbundlejar);
Enumeration<? extends ZipEntry> files = zipFile.entries();
File f = null;
FileOutputStream fos = null;
while (files.hasMoreElements()) {
try {
ZipEntry entry = files.nextElement();
String entryName = entry.getName();
if (!entryName.startsWith("jettyhome")) {
continue;
}
InputStream eis = zipFile.getInputStream(entry);
byte[] buffer = new byte[1024];
int bytesRead = 0;
f = new File(parentOfMagicJettyHome, entry.getName());
if (entry.isDirectory()) {
f.mkdirs();
} else {
f.getParentFile().mkdirs();
f.createNewFile();
fos = new FileOutputStream(f);
while ((bytesRead = eis.read(buffer)) != -1) {
fos.write(buffer, 0, bytesRead);
}
}
} catch (IOException e) {
e.printStackTrace();
continue;
} finally {
if (fos != null) {
try { fos.close(); } catch (IOException e) {}
fos = null;
}
}
}
} finally {
if (zipFile != null) try { zipFile.close(); } catch (Throwable t) {}
}
}
/**
* Look for the parent folder that contains jettyhome.
* Can be specified by the sys property jetty.magic.home.parent
* or if inside the pde will default on the configuration area.
* Otherwise returns null.
*
* @return The folder inside which jettyhome should be placed.
*/
private static File getParentFolderOfMagicHome() {
// for (java.util.Map.Entry<Object, Object> e : System.getProperties().entrySet()) {
// System.err.println(e.getKey() + " -> " + e.getValue());
// }
String magicParent = System.getProperty("jetty.magic.home.parent");
String magicParentValue = magicParent != null ? System.getProperty(magicParent) : null;
File specifiedMagicParent = magicParentValue != null
? getFile(magicParentValue) //in that case it was pointing to another system property.
: getFile(magicParent); //in that case it was directly a file.
if (specifiedMagicParent != null && specifiedMagicParent.exists()) {
return specifiedMagicParent;
}
if (isPDEDevelopment()) {
return getConfigurationAreaDirectory();
}
return null;
}
/**
* Be flexible with the url/uri/path that can be the value of the various
* system properties.
* @param file
* @return a file. might not exist.
*/
private static File getFile(String file) {
if (file == null) {
return null;
}
try {
if (file.startsWith("file:/")) {
if (!file.startsWith("file://")) {
return new File(new URI(file));
} else {
return new File(new URL(file).toURI());
}
} else {
return new File(file);
}
} catch (Throwable t) {
t.printStackTrace();
return new File(file);
}
}
}

View File

@ -0,0 +1,108 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.boot.internal.webapp;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import org.eclipse.jetty.server.Server;
/**
* Helper to create a URL class-loader with the jars inside ${jetty.home}/lib/ext
* and ${jetty.home}/resources.
* In an ideal world, every library is an OSGi bundle that does loads nicely.
* To support standard jars or bundles that cannot be loaded in the current
* OSGi environment, we support inserting the jars in the usual jetty/lib/ext
* folders in the proper classpath for the webapps.
* <p>
* For example the test-jndi webapplication depends on derby, derbytools, atomikos
* none of them are osgi bundles.
* we can either re-package them or we can place them in the usual lib/ext.
* <br/>In fact jasper's jsp libraries should maybe place in lib/ext too.
* </p>
* <p>
* The drawback is that those libraries will not be available in the OSGi classloader.
* Note that we could have setup those jars as embedded jars of the current bundle.
* However, we would need to know in advance what are those jars which was not acceptable.
* Also having those jars in a URLClassLoader seem to be required for some cases.
* For example jaspers' TldLocationsCache (replaced by TldScanner for servlet-3.0).
* <br/>
* Also all the dependencies of those libraries must be resolvable directly
* from the JettyBooStrapper bundle as it is set as the parent classloader.
* For example: if atomikos is placed in lib/ext
* it will work if and only if JettyBootStrapper import the necessary packages
* from javax.naming*, javax.transaction*, javax.mail* etc
* Most of the common cases of javax are added as optional import packages into
* jetty bootstrapper plugin. When there are not covered: please make a request
* or create a fragment or register a bundle with a buddy-policy onto the jetty bootstrapper..
* </p>
* <p>
* Alternatives to placing jars in lib/ext
* <ol>
* <li>Bundle the jars in an osgi bundle. Have the webapp(s) that context depends on them
* depend on that bundle. Things will go well for jetty.</li>
* <li>Bundle those jars in an osgi bundle-fragment that targets the jetty-bootstrap bundle</li>
* <li>Use equinox Buddy-Policy: register a buddy of the jetty bootstrapper bundle.
* (least favorite: it will work only on equinox)</li>
* </ol>
* </p>
*/
public class LibExtClassLoaderHelper {
/**
* @param server
* @return a url classloader with the jars of lib/ext. The parent classloader
* usuall is the JettyBootStrapper.
* @throws MalformedURLException
*/
public static ClassLoader createLibEtcClassLoaderHelper(File jettyHome, Server server,
ClassLoader parentClassLoader)
throws MalformedURLException {
ArrayList<URL> urls = new ArrayList<URL>();
File jettyResources = new File(jettyHome, "resources");
if (jettyResources.exists()) {
//make sure it contains something else than README:
for (File f : jettyResources.listFiles()) {
if (f.getName().toLowerCase().startsWith("readme")) {
continue;
} else {
urls.add(jettyResources.toURI().toURL());
break;
}
}
}
File libEtc = new File(jettyHome, "lib/ext");
for (File f : libEtc.listFiles()) {
if (f.getName().endsWith(".jar")) {
//cheap to tolerate folders so let's do it.
URL url = f.toURI().toURL();
if (f.isFile()) {//is this necessary anyways?
url = new URL("jar:" + url.toString() + "!/");
}
urls.add(url);
}
}
if (urls.isEmpty()) {
return parentClassLoader;
}
return new URLClassLoader(urls.toArray(new URL[urls.size()]),
parentClassLoader);
}
}

View File

@ -0,0 +1,863 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.boot.internal.webapp;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.jetty.deploy.ConfigurationManager;
import org.eclipse.jetty.deploy.ContextDeployer;
import org.eclipse.jetty.deploy.WebAppDeployer;
import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator;
import org.eclipse.jetty.osgi.boot.internal.jsp.TldLocatableURLClassloader;
import org.eclipse.jetty.osgi.boot.internal.jsp.TldLocatableURLClassloaderWithInsertedJettyClassloader;
import org.eclipse.jetty.osgi.boot.utils.BundleClassLoaderHelper;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
import org.eclipse.jetty.osgi.boot.utils.WebappRegistrationCustomizer;
import org.eclipse.jetty.osgi.boot.utils.internal.DefaultBundleClassLoaderHelper;
import org.eclipse.jetty.osgi.boot.utils.internal.DefaultFileLocatorHelper;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.util.AttributesMap;
import org.eclipse.jetty.webapp.JettyWebXmlConfiguration;
import org.eclipse.jetty.webapp.WebAppClassLoader;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebXmlConfiguration;
import org.eclipse.jetty.xml.XmlConfiguration;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.xml.sax.SAXException;
/**
* Bridges the traditional web-application deployers: {@link WebAppDeployer} and {@link ContextDeployer} with the OSGi lifecycle where applications are managed
* inside OSGi-bundles.
* <p>
* This class should be called as a consequence of the activation of a new service that is a ContextHandler.<br/>
* This way the new webapps are exposed as OSGi services.
* </p>
* <p>
* Helper methods to register a bundle that is a web-application or a context. It is deployed as if the server was using its WebAppDeployer or ContextDeployer
* as configured in its etc/jetty.xml file. Well as close as possible to that.
* </p>
* Limitations:
* <ul>
* <li>support for jarred webapps is somewhat limited.</li>
* </ul>
*/
class WebappRegistrationHelper
{
private static boolean INITIALIZED = false;
/** By default set to: {@link DefaultBundleClassLoaderHelper}. It supports equinox and apache-felix
* fragment bundles that are specific to an OSGi implementation should set a different implementation. */
public static BundleClassLoaderHelper BUNDLE_CLASS_LOADER_HELPER = null;
/** By default set to: {@link DefaultBundleClassLoaderHelper}. It supports equinox and apache-felix
* fragment bundles that are specific to an OSGi implementation should set a different implementation. */
public static BundleFileLocatorHelper BUNDLE_FILE_LOCATOR_HELPER = null;
/** By default set to: {@link DefaultBundleClassLoaderHelper}. It supports equinox and apache-felix
* fragment bundles that are specific to an OSGi implementation should set a different implementation. */
public static WebappRegistrationCustomizer JSP_REGISTRATION_HELPER = null;
private Server _server;
private ContextDeployer _ctxtDeployer;
private WebAppDeployer _webappDeployer;
private ContextHandlerCollection _ctxtHandler;
/**
* this class loader loads the jars inside {$jetty.home}/lib/ext it is meant as a migration path and for jars that are not OSGi ready.
*/
private ClassLoader _libEtcClassLoader;
public WebappRegistrationHelper(Server server)
{
_server = server;
staticInit();
}
//Inject the customizing classes that might be defined in fragment bundles.
private static synchronized void staticInit() {
if (!INITIALIZED) {
INITIALIZED = true;
//setup the custom WebappRegistrationCustomizer
try
{
Class<?> cl = Class.forName(WebappRegistrationCustomizer.CLASS_NAME);
JSP_REGISTRATION_HELPER = (WebappRegistrationCustomizer)
cl.newInstance();
}
catch (Throwable t)
{
// System.err.println("no jsp/jasper support");
// System.exit(1);
}
//setup the custom BundleClassLoaderHelper
try
{
BUNDLE_CLASS_LOADER_HELPER = (BundleClassLoaderHelper)
Class.forName(BundleClassLoaderHelper.CLASS_NAME).newInstance();
}
catch (Throwable t)
{
// System.err.println("support for equinox and felix");
BUNDLE_CLASS_LOADER_HELPER = new DefaultBundleClassLoaderHelper();
}
//setup the custom FileLocatorHelper
try
{
BUNDLE_FILE_LOCATOR_HELPER = (BundleFileLocatorHelper)
Class.forName(BundleFileLocatorHelper.CLASS_NAME).newInstance();
}
catch (Throwable t)
{
// System.err.println("no jsp/jasper support");
BUNDLE_FILE_LOCATOR_HELPER = new DefaultFileLocatorHelper();
}
}
}
/**
* Look for the home directory of jetty as defined by the system property 'jetty.home'. If undefined, look at the current bundle and uses its own jettyhome
* folder for this feature.
* <p>
* Special case: inside eclipse-SDK:<br/>
* If the bundle is jarred, see if we are inside eclipse-PDE itself. In that case, look for the installation directory of eclipse-PDE, try to create a
* jettyhome folder there and install the sample jettyhome folder at that location. This makes the installation in eclipse-SDK easier.
* </p>
*
* @param context
* @throws Exception
*/
public void setup(BundleContext context, Map<String, String> configProperties) throws Exception
{
File _installLocation = BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(context.getBundle());
// debug:
// new File("~/proj/eclipse-install/eclipse-3.5.1-SDK-jetty7/" +
// "dropins/jetty7/plugins/org.eclipse.jetty.osgi.boot_0.0.1.001-SNAPSHOT.jar");
boolean bootBundleCanBeJarred = true;
String jettyHome = System.getProperty("jetty.home");
if (jettyHome == null || jettyHome.length() == 0)
{
if (_installLocation.getName().endsWith(".jar"))
{
jettyHome = JettyHomeHelper.setupJettyHomeInEclipsePDE(_installLocation);
}
if (jettyHome == null)
{
jettyHome = _installLocation.getAbsolutePath() + "/jettyhome";
bootBundleCanBeJarred = false;
}
System.setProperty("jetty.home",jettyHome);
}
String jettyLogs = System.getProperty("jetty.logs");
if (jettyLogs == null || jettyLogs.length() == 0)
{
System.setProperty("jetty.logs",System.getProperty("jetty.home") + "/logs");
}
if (!bootBundleCanBeJarred && !_installLocation.isDirectory())
{
String install = _installLocation != null?_installLocation.getCanonicalPath():" unresolved_install_location";
throw new IllegalArgumentException("The system property -Djetty.home" + " must be set to a directory or the bundle "
+ context.getBundle().getSymbolicName() + " installed here " + install + " must be unjarred.");
}
try
{
System.err.println("JETTY_HOME set to " + new File(jettyHome).getCanonicalPath());
}
catch (Throwable t)
{
System.err.println("JETTY_HOME _set to " + new File(jettyHome).getAbsolutePath());
}
ClassLoader contextCl = Thread.currentThread().getContextClassLoader();
try
{
XmlConfiguration config = new XmlConfiguration(new FileInputStream(jettyHome + "/etc/jetty.xml"));
config.getProperties().put("jetty.home", jettyHome);
// passing this bundle's classloader as the context classlaoder
// makes sure there is access to all the jetty's bundles
File jettyHomeF = new File(jettyHome);
try
{
_libEtcClassLoader = LibExtClassLoaderHelper.createLibEtcClassLoaderHelper(jettyHomeF,_server,JettyBootstrapActivator.class.getClassLoader());
}
catch (MalformedURLException e)
{
e.printStackTrace();
}
Thread.currentThread().setContextClassLoader(_libEtcClassLoader);
config.configure(_server);
init();
_server.start();
// _server.join();
}
catch (Throwable t)
{
t.printStackTrace();
}
finally
{
Thread.currentThread().setContextClassLoader(contextCl);
}
}
/**
* Must be called after the server is configured.
*
* Locate the actual instance of the ContextDeployer and WebAppDeployer that was created when configuring the server through jetty.xml. If there is no such
* thing it won't be possible to deploy webapps from a context and we throw IllegalStateExceptions.
*/
private void init()
{
// [Hugues] if no jndi is setup let's do it.
// we could also get the bundle for jetty-jndi and open the corresponding properties file
// instead of hardcoding the values: but they are unlikely to change.
if (System.getProperty("java.naming.factory.initial") == null)
{
System.setProperty("java.naming.factory.initial","org.eclipse.jetty.jndi.InitialContextFactory");
}
if (System.getProperty("java.naming.factory.url.pkgs") == null)
{
System.setProperty("java.naming.factory.url.pkgs","org.eclipse.jetty.jndi");
}
_ctxtHandler = (ContextHandlerCollection)_server.getChildHandlerByClass(ContextHandlerCollection.class);
if (_ctxtHandler == null)
{
throw new IllegalStateException("ERROR: No ContextHandlerCollection was configured" + " with the server to add applications to."
+ "Using a default one is not supported at" + " this point. " + " Please review the jetty.xml file used.");
}
List<ContextDeployer> ctxtDeployers = _server.getBeans(ContextDeployer.class);
if (ctxtDeployers == null || ctxtDeployers.isEmpty())
{
System.err.println("Warn: No ContextDeployer was configured" + " with the server. Using a default one is not supported at" + " this point. "
+ " Please review the jetty.xml file used.");
}
else
{
_ctxtDeployer = ctxtDeployers.get(0);
}
List<WebAppDeployer> wDeployers = _server.getBeans(WebAppDeployer.class);
if (wDeployers == null || wDeployers.isEmpty())
{
System.err.println("Warn: No WebappDeployer was configured" + " with the server. Using a default one is not supported at" + " this point. "
+ " Please review the jetty.xml file used.");
}
else
{
_webappDeployer = (WebAppDeployer)wDeployers.get(0);
}
}
/**
* Deploy a new web application on the jetty server.
*
* @param context
* The current bundle context
* @param webappFolderPath
* The path to the root of the webapp. Must be a path relative to bundle; either an absolute path.
* @param contextPath
* The context path. Must start with "/"
* @param classInBundle
* A class that belongs to the current bundle to inherit from the osgi classloader. Null to not have access to the OSGI classloader.
* @throws Exception
*/
public ContextHandler registerWebapplication(Bundle bundle, String webappFolderPath, String contextPath) throws Exception
{
File bundleInstall = BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(bundle);
File webapp = webappFolderPath != null && webappFolderPath.length() != 0
&& !webappFolderPath.equals(".")
? new File(bundleInstall,webappFolderPath)
: bundleInstall;
if (!webapp.exists())
{
throw new IllegalArgumentException("Unable to locate "
+ webappFolderPath + " inside "
+ (bundleInstall != null
? bundleInstall.getAbsolutePath()
: "unlocated bundle '" + bundle.getSymbolicName() + "'"));
}
return registerWebapplication(bundle,webapp,contextPath);
}
/**
* @See {@link WebAppDeployer#scan()}
*
* @param webapp
* @param contextPath
* @param classInBundle
* @return The contexthandler created and started
* @throws Exception
*/
public ContextHandler registerWebapplication(Bundle contributor, File webapp, String contextPath) throws Exception
{
ClassLoader contextCl = Thread.currentThread().getContextClassLoader();
String[] oldServerClasses = null;
WebAppContext context = null;
try
{
// make sure we provide access to all the jetty bundles by going through this bundle.
TldLocatableURLClassloader composite = createContextClassLoader(contributor);
// configure with access to all jetty classes and also all the classes
// that the contributor gives access to.
Thread.currentThread().setContextClassLoader(composite);
context = new WebAppContext(webapp.getAbsolutePath(),contextPath);
WebXmlConfiguration webXml = new WebXmlConfiguration();
webXml.configure(context);
JettyWebXmlConfiguration jettyXml = new JettyWebXmlConfiguration();
jettyXml.configure(context);
configureWebAppContext(context);
// ok now register this webapp. we checked when we started jetty that there
// was at least one such handler for webapps.
_ctxtHandler.addHandler(context);
configureContextClassLoader(context,composite);
// @see org.eclipse.jetty.webapp.JettyWebXmlConfiguration#configure(WebAppContext)
oldServerClasses = context.getServerClasses();
context.setServerClasses(null);
context.start();
return context;
}
finally
{
if (context != null)
{
context.setServerClasses(oldServerClasses);
}
Thread.currentThread().setContextClassLoader(contextCl);
}
}
/**
* Stop a ContextHandler and remove it from the collection.
*
* @See ContextDeployer#undeploy
* @param contextHandler
* @throws Exception
*/
public void unregister(ContextHandler contextHandler) throws Exception
{
contextHandler.stop();
_ctxtHandler.removeHandler(contextHandler);
}
/**
* @return The folder in which the context files of the osgi bundles are
* located and watched. Or null when the system property
* "jetty.osgi.contexts.home" is not defined.
*/
File getOSGiContextsHome()
{
String jettyContextsHome = System.getProperty("jetty.osgi.contexts.home");
if (jettyContextsHome != null)
{
File contextsHome = new File(jettyContextsHome);
if (!contextsHome.exists() || !contextsHome.isDirectory())
{
throw new IllegalArgumentException("the ${jetty.osgi.contexts.home} '" + jettyContextsHome + " must exist and be a folder");
}
return contextsHome;
}
return null;
}
/**
* This type of registration relies on jetty's complete context xml file.
* Context encompasses jndi and all other things.
* This makes the definition of the webapp a lot more self-contained.
*
* @param webapp
* @param contextPath
* @param classInBundle
* @throws Exception
*/
public ContextHandler registerContext(Bundle contributor, String contextFileRelativePath) throws Exception
{
File contextsHome = getOSGiContextsHome();
if (contextsHome != null)
{
File prodContextFile = new File(contextsHome,contributor.getSymbolicName() + "/" + contextFileRelativePath);
if (prodContextFile.exists())
{
return registerContext(contributor,prodContextFile);
}
}
File contextFile = new File(BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(contributor),contextFileRelativePath);
if (contextFile.exists())
{
return registerContext(contributor,contextFile);
}
else
{
if (contextFileRelativePath.startsWith("./"))
{
contextFileRelativePath = contextFileRelativePath.substring(1);
}
if (!contextFileRelativePath.startsWith("/"))
{
contextFileRelativePath = "/" + contextFileRelativePath;
}
URL contextURL = contributor.getEntry(contextFileRelativePath);
if (contextURL != null)
{
return registerContext(contributor,contextURL.openStream());
}
throw new IllegalArgumentException("Could not find the context " + "file " + contextFileRelativePath + " for the bundle "
+ contributor.getSymbolicName());
}
}
/**
* This type of registration relies on jetty's complete context xml file.
* Context encompasses jndi and all other things. This makes the definition of the
* webapp a lot more self-contained.
*
* @param webapp
* @param contextPath
* @param classInBundle
* @throws Exception
*/
private ContextHandler registerContext(Bundle contributor, File contextFile) throws Exception
{
InputStream contextFileInputStream = null;
try
{
contextFileInputStream = new BufferedInputStream(new FileInputStream(contextFile));
return registerContext(contributor,contextFileInputStream);
}
finally
{
if (contextFileInputStream != null)
try
{
contextFileInputStream.close();
}
catch (IOException ioe)
{
}
}
}
private ContextHandler registerContext(Bundle contributor, InputStream contextFileInputStream) throws Exception
{
ClassLoader contextCl = Thread.currentThread().getContextClassLoader();
String[] oldServerClasses = null;
WebAppContext webAppContext = null;
try
{
// make sure we provide access to all the jetty bundles by going through this bundle.
TldLocatableURLClassloader composite = createContextClassLoader(contributor);
// configure with access to all jetty classes and also all the classes
// that the contributor gives access to.
Thread.currentThread().setContextClassLoader(composite);
ContextHandler context = createContextHandler(contributor,contextFileInputStream);
// //[H]extra work for the path to the file:
// if (context instanceof WebAppContext) {
// WebAppContext wah = (WebAppContext)context;
// Resource.newResource(wah.getWar());
// }
// ok now register this webapp. we checked when we started jetty that there
// was at least one such handler for webapps.
_ctxtHandler.addHandler(context);
configureContextClassLoader(context,composite);
if (context instanceof WebAppContext)
{
webAppContext = (WebAppContext)context;
// @see org.eclipse.jetty.webapp.JettyWebXmlConfiguration#configure(WebAppContext)
oldServerClasses = webAppContext.getServerClasses();
webAppContext.setServerClasses(null);
}
context.start();
return context;
}
finally
{
if (webAppContext != null)
{
webAppContext.setServerClasses(oldServerClasses);
}
Thread.currentThread().setContextClassLoader(contextCl);
}
}
/**
* TODO: right now only the jetty-jsp bundle is scanned for common taglibs. Should support a way to plug more bundles that contain taglibs.
*
* The jasper TldScanner expects a URLClassloader to parse a jar for the /META-INF/*.tld it may contain. We place the bundles that we know contain such
* tag-libraries. Please note that it will work if and only if the bundle is a jar (!) Currently we just hardcode the bundle that contains the jstl
* implemenation.
*
* A workaround when the tld cannot be parsed with this method is to copy and paste it inside the WEB-INF of the webapplication where it is used.
*
* Support only 2 types of packaging for the bundle: - the bundle is a jar (recommended for runtime.) - the bundle is a folder and contain jars in the root
* and/or in the lib folder (nice for PDE developement situations) Unsupported: the bundle is a jar that embeds more jars.
*
* @return
* @throws Exception
*/
private URL[] getJarsWithTlds() throws Exception
{
if (JSP_REGISTRATION_HELPER != null)
{
return JSP_REGISTRATION_HELPER.getJarsWithTlds(BUNDLE_FILE_LOCATOR_HELPER);
}
else
{
return null;
}
}
/**
* Applies the properties of WebAppDeployer as defined in jetty.xml.
*
* @see {WebAppDeployer#scan} around the comment <code>// configure it</code>
*/
protected void configureWebAppContext(WebAppContext wah)
{
// configure it
// wah.setContextPath(context);
String[] _configurationClasses = _webappDeployer.getConfigurationClasses();
String _defaultsDescriptor = _webappDeployer.getDefaultsDescriptor();
boolean _parentLoaderPriority = _webappDeployer.isParentLoaderPriority();
AttributesMap _contextAttributes = getWebAppDeployerContextAttributes();
if (_configurationClasses != null)
wah.setConfigurationClasses(_configurationClasses);
if (_defaultsDescriptor != null)
wah.setDefaultsDescriptor(_defaultsDescriptor);
// wah.setExtractWAR(_extract);//[H]should we force to extract ?
// wah.setWar(app.toString());//[H]should we force to extract ?
wah.setParentLoaderPriority(_parentLoaderPriority);
// set up any contextAttributes
wah.setAttributes(new AttributesMap(_contextAttributes));
}
/**
* @See {@link ContextDeployer#scan}
* @param contextFile
* @return
*/
protected ContextHandler createContextHandler(Bundle bundle, File contextFile)
{
try
{
return createContextHandler(bundle,new BufferedInputStream(new FileInputStream(contextFile)));
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
return null;
}
/**
* @See {@link ContextDeployer#scan}
* @param contextFile
* @return
*/
@SuppressWarnings("unchecked")
protected ContextHandler createContextHandler(Bundle bundle, InputStream contextInputStream)
{
/*
* Do something identical to what the ContextDeployer would have done: XmlConfiguration xmlConfiguration=new XmlConfiguration(resource.getURL());
* HashMap properties = new HashMap(); properties.put("Server", _contexts.getServer()); if (_configMgr!=null)
* properties.putAll(_configMgr.getProperties());
*
* xmlConfiguration.setProperties(properties); ContextHandler context=(ContextHandler)xmlConfiguration.configure(); context.setAttributes(new
* AttributesMap(_contextAttributes));
*/
ConfigurationManager _configMgr = getContextDeployerConfigurationManager();
AttributesMap _contextAttributes = getContextDeployerContextAttributes();
try
{
XmlConfiguration xmlConfiguration = new XmlConfiguration(contextInputStream);
HashMap<String, Object> properties = new HashMap<String, Object>();
properties.put("Server",_server);
if (_configMgr != null)
{
properties.putAll(_configMgr.getProperties());
}
// insert the bundle's location as a property.
setThisBundleHomeProperty(bundle,properties);
xmlConfiguration.setProperties(properties);
// bug in equinox? if jetty plus is an optionally required-bundle, then we can't load the class!
// JettyBootstrapActivator.class.getClassLoader().loadClass("org.eclipse.jetty.plus.jndi.EnvEntry");
// FrameworkUtil.getBundle(JettyBootstrapActivator.class).loadClass("org.eclipse.jetty.plus.jndi.EnvEntry");
// in fact the pde can't find it at compilation time and shows a warning "Unsatisfied version constraint: ..."
// System.err.println(EnvEntry.class);
ContextHandler context = (ContextHandler)xmlConfiguration.configure();
context.setAttributes(new AttributesMap(_contextAttributes));
// rfc-66:
context.setAttribute("osgi-bundlecontext",bundle.getBundleContext());
return context;
}
catch (FileNotFoundException e)
{
return null;
}
catch (SAXException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (Throwable e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
finally
{
if (contextInputStream != null)
try
{
contextInputStream.close();
}
catch (IOException ioe)
{
}
}
return null;
}
/**
* Configure a classloader onto the context. If the context is a WebAppContext, build a WebAppClassLoader that has access to all the jetty classes thanks to
* the classloader of the JettyBootStrapper bundle and also has access to the classloader of the bundle that defines this context.
* <p>
* If the context is not a WebAppContext, same but with a simpler URLClassLoader. Note that the URLClassLoader is pretty much fake: it delegate all actual
* classloading to the parent classloaders.
* </p>
* <p>
* The URL[] returned by the URLClassLoader create contained specifically the jars that some j2ee tools expect and look into. For example the jars that
* contain tld files for jasper's jstl support.
* </p>
*
* @param context
* @param contributor
* @param webapp
* @param contextPath
* @param classInBundle
* @throws Exception
*/
protected void configureContextClassLoader(ContextHandler context, TldLocatableURLClassloader composite) throws Exception
{
if (context instanceof WebAppContext)
{
WebAppContext webappCtxt = (WebAppContext)context;
// updateServerClasses(webappCtxt);
WebAppClassLoader wcl = new WebAppClassLoader(composite,webappCtxt);
// addJarsWithTlds(wcl);
context.setClassLoader(wcl);
}
else
{
context.setClassLoader(composite);
}
}
/**
* Right now we avoid this by doing what JettWebXmlConfiguration is doing during the configureWebapp method call: set the serverclasses to null and when
* done put back the limitations as defined.
*
* We need to test that though.
*
* TODO: review this with the jetty team: how do you let cometd cleanly access jetty-client, jetty-io, jetty-http from osgi? The webapp-classloader of jetty
* refuses to delegate loading the class to the parent classloader if that class belongs to the org.eclipse.jetty package or one of its descendants: make
* sure they isolate the webapp from the server.
*
* Maybe we need to somehow chagne the way we buidl the webappcontext classloader so that the osgi classloader is not the parent of the webappclassloader.
*
*/
private static String[] visibleinOsgi = new String[]
{ "-org.eclipse.jetty.util.", "-org.eclipse.jetty.io.", "-org.eclipse.jetty.client.", "-org.eclipse.jetty.http.", "-org.eclipse.jetty.osgi." };
/**
* @deprecated not so good.
* @see WebAppContext#setServerClasses(String[]) We make org.eclipse.jetty.osgi visible if they are hidden.
*/
private void updateServerClasses(WebAppContext webappCtxt)
{
String[] serverClasses = webappCtxt.getServerClasses();
for (String s : serverClasses)
{
if (s.startsWith("-org.eclipse.jetty.osgi."))
{
return;// ok already visible
}
}
String[] serverClasses2 = new String[serverClasses.length + visibleinOsgi.length];
System.arraycopy(visibleinOsgi,0,serverClasses2,0,visibleinOsgi.length);
System.arraycopy(serverClasses,0,serverClasses2,visibleinOsgi.length,serverClasses.length);
webappCtxt.setServerClasses(serverClasses2);
}
protected TldLocatableURLClassloader createContextClassLoader(Bundle contributor) throws Exception
{
ClassLoader osgiCl = BUNDLE_CLASS_LOADER_HELPER.getBundleClassLoader(contributor);
if (osgiCl != null)
{
// this solution does not insert all the jetty related classes in the webapp's classloader:
// WebAppClassLoader cl = new WebAppClassLoader(classInBundle.getClassLoader(), context);
// context.setClassLoader(cl);
// Make all of the jetty's classes available to the webapplication classloader
// also add the contributing bundle's classloader to give access to osgi to
// the contributed webapp.
TldLocatableURLClassloader composite =
new TldLocatableURLClassloaderWithInsertedJettyClassloader(
_libEtcClassLoader,osgiCl, getJarsWithTlds());
return composite;
}
else
{
// Make all of the jetty's classes available to the webapplication classloader
TldLocatableURLClassloader composite = new TldLocatableURLClassloader(
_libEtcClassLoader,getJarsWithTlds());
return composite;
}
}
/**
* Set the property &quot;this.bundle.install&quot; to point to the location of the bundle. Useful when <SystemProperty name="this.bundle.home"/> is used.
*/
private void setThisBundleHomeProperty(Bundle bundle, HashMap<String, Object> properties)
{
try
{
File location = BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(bundle);
properties.put("this.bundle.install",location.getCanonicalPath());
}
catch (Throwable t)
{
System.err.println("Unable to set 'this.bundle.install' " + " for the bundle " + bundle.getSymbolicName());
t.printStackTrace();
}
}
// some private suff in ContextDeployer that we need to
// be faithful to the ContextDeployer definition created in etc/jetty.xml
// kindly ask to have a public getter for those?
private static Field CONTEXT_DEPLOYER_CONFIGURATION_MANAGER_FIELD = null;
private static Field CONTEXT_DEPLOYER_CONTEXT_ATTRIBUTES_FIELD = null;
private ConfigurationManager getContextDeployerConfigurationManager()
{
try
{
if (CONTEXT_DEPLOYER_CONFIGURATION_MANAGER_FIELD == null)
{
CONTEXT_DEPLOYER_CONFIGURATION_MANAGER_FIELD = ContextDeployer.class.getDeclaredField("_configMgr");
CONTEXT_DEPLOYER_CONFIGURATION_MANAGER_FIELD.setAccessible(true);
}
return (ConfigurationManager)CONTEXT_DEPLOYER_CONFIGURATION_MANAGER_FIELD.get(_ctxtDeployer);
}
catch (Throwable t)
{
t.printStackTrace();
}
return null;
}
private AttributesMap getContextDeployerContextAttributes()
{
try
{
if (CONTEXT_DEPLOYER_CONTEXT_ATTRIBUTES_FIELD == null)
{
CONTEXT_DEPLOYER_CONTEXT_ATTRIBUTES_FIELD = ContextDeployer.class.getDeclaredField("_contextAttributes");
CONTEXT_DEPLOYER_CONTEXT_ATTRIBUTES_FIELD.setAccessible(true);
}
return (AttributesMap)CONTEXT_DEPLOYER_CONTEXT_ATTRIBUTES_FIELD.get(_ctxtDeployer);
}
catch (Throwable t)
{
t.printStackTrace();
}
return null;
}
private static Field WEBAPP_DEPLOYER_CONTEXT_ATTRIBUTES_FIELD = null;
private AttributesMap getWebAppDeployerContextAttributes()
{
try
{
if (WEBAPP_DEPLOYER_CONTEXT_ATTRIBUTES_FIELD == null)
{
WEBAPP_DEPLOYER_CONTEXT_ATTRIBUTES_FIELD = WebAppDeployer.class.getDeclaredField("_contextAttributes");
WEBAPP_DEPLOYER_CONTEXT_ATTRIBUTES_FIELD.setAccessible(true);
}
return (AttributesMap)WEBAPP_DEPLOYER_CONTEXT_ATTRIBUTES_FIELD.get(_webappDeployer);
}
catch (Throwable t)
{
t.printStackTrace();
}
return null;
}
}

View File

@ -0,0 +1,42 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.boot.utils;
import org.osgi.framework.Bundle;
/**
* Is there a clean OSGi way to go from the Bundle object to the classloader of the Bundle ?
* You can certainly take a class inside the bundle and get the bundle's classloader
* that way. Getting the classloader directly from the bundle would be nice.
* <p>
* We could use fragments that are specific to each OSGi implementation.
* Using introspection here to keep packaging simple and avoid the multiplication of the jars.
* </p>
* <p>
* The default implementation relies on introspection and supports equinox-3.5 and felix-2.0.0
* </p>
*/
public interface BundleClassLoaderHelper
{
/** The name of the custom implementation for this interface in a fragment. */
public static final String CLASS_NAME = "org.eclipse.jetty.osgi.boot.utils.BundleClassLoaderHelperImpl";
/**
* @return The classloader of a given bundle. Assuming the bundle is started.
*/
public ClassLoader getBundleClassLoader(Bundle bundle);
}

View File

@ -0,0 +1,70 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.boot.utils;
import java.io.File;
import org.osgi.framework.Bundle;
/**
* From a bundle to its location on the filesystem. Assumes the bundle is not a jar.
*
* @author hmalphettes
*/
public interface BundleFileLocatorHelper
{
/** The name of the custom implementation for this interface in a fragment. */
public static final String CLASS_NAME = "org.eclipse.jetty.osgi.boot.utils.FileLocatorHelperImpl";
/**
* Works with equinox, felix, nuxeo and probably more. Not exactly in the
* spirit of OSGi but quite necessary to support self-contained webapps and other
* situations.
* <p>
* Currently only works with bundles that are not jar.
* </p>
*
* @param bundle
* The bundle
* @return Its installation location as a file.
* @throws Exception
*/
public File getBundleInstallLocation(Bundle bundle) throws Exception;
/**
* Locate a file inside a bundle.
*
* @param bundle
* @param path
* @return
* @throws Exception
*/
public File getFileInBundle(Bundle bundle, String path) throws Exception;
/**
* If the bundle is a jar, returns the jar. If the bundle is a folder, look inside it and search for jars that it returns.
* <p>
* Good enough for our purpose (TldLocationsCache when it scans for tld files inside jars alone.
* In fact we only support the second situation for
* development purpose where the bundle was imported in pde and the classes kept in a jar.
* </p>
*
* @param bundle
* @return The jar(s) file that is either the bundle itself, either the jars embedded inside it.
*/
public File[] locateJarsInsideBundle(Bundle bundle) throws Exception;
}

View File

@ -0,0 +1,48 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.boot.utils;
import java.net.URL;
/**
* Fix various shortcomings with the way jasper parses the tld files.
*/
public interface WebappRegistrationCustomizer
{
/** we could do something a lot more pluggable with
* a custom header in the manifest or some customer declarative services
* let's keep it simple for now. hopefully the rest of the world
* won't need to customize this. */
public static final String CLASS_NAME = "org.eclipse.jetty.osgi.boot.jasper.WebappRegistrationCustomizerImpl";
/**
* TODO: right now only the jetty-jsp bundle is scanned for common taglibs. Should support a way to plug more bundles that contain taglibs.
*
* The jasper TldScanner expects a URLClassloader to parse a jar for the /META-INF/*.tld it may contain. We place the bundles that we know contain such
* tag-libraries. Please note that it will work if and only if the bundle is a jar (!) Currently we just hardcode the bundle that contains the jstl
* implemenation.
*
* A workaround when the tld cannot be parsed with this method is to copy and paste it inside the WEB-INF of the webapplication where it is used.
*
* Support only 2 types of packaging for the bundle: - the bundle is a jar (recommended for runtime.) - the bundle is a folder and contain jars in the root
* and/or in the lib folder (nice for PDE developement situations) Unsupported: the bundle is a jar that embeds more jars.
*
* @return
* @throws Exception
*/
URL[] getJarsWithTlds(BundleFileLocatorHelper fileLocator) throws Exception;
}

View File

@ -0,0 +1,181 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.boot.utils.internal;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.eclipse.jetty.osgi.boot.utils.BundleClassLoaderHelper;
import org.osgi.framework.Bundle;
/**
* Default implementation of the BundleClassLoaderHelper.
* Uses introspection to support equinox-3.5 and felix-2.0.0
*/
public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper
{
private static boolean identifiedOsgiImpl = false;
private static boolean isEquinox = false;
private static boolean isFelix = false;
private static void init(Bundle bundle)
{
identifiedOsgiImpl = true;
try
{
isEquinox = bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.framework.internal.core.BundleHost") != null;
}
catch (Throwable t)
{
isEquinox = false;
}
if (!isEquinox)
{
try
{
isFelix = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.BundleImpl") != null;
}
catch (Throwable t2)
{
isFelix = false;
}
}
// System.err.println("isEquinox=" + isEquinox);
// System.err.println("isFelix=" + isFelix);
}
/**
* Assuming the bundle is started.
*
* @param bundle
* @return
*/
public ClassLoader getBundleClassLoader(Bundle bundle)
{
String bundleActivator = (String)bundle.getHeaders().get("Bundle-Activator");
if (bundleActivator == null)
{
bundleActivator = (String)bundle.getHeaders().get("Jetty-ClassInBundle");
}
if (bundleActivator != null)
{
try
{
return bundle.loadClass(bundleActivator).getClassLoader();
}
catch (ClassNotFoundException e)
{
// should not happen as we are called if the bundle is started anyways.
e.printStackTrace();
}
}
// resort to introspection
if (!identifiedOsgiImpl)
{
init(bundle);
}
if (isEquinox)
{
return internalGetEquinoxBundleClassLoader(bundle);
}
else if (isFelix)
{
return internalGetFelixBundleClassLoader(bundle);
}
return null;
}
private static Method Equinox_BundleHost_getBundleLoader_method;
private static Method Equinox_BundleLoader_createClassLoader_method;
private static ClassLoader internalGetEquinoxBundleClassLoader(Bundle bundle)
{
// assume equinox:
try
{
if (Equinox_BundleHost_getBundleLoader_method == null)
{
Equinox_BundleHost_getBundleLoader_method = bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.framework.internal.core.BundleHost")
.getDeclaredMethod("getBundleLoader",new Class[] {});
Equinox_BundleHost_getBundleLoader_method.setAccessible(true);
}
Object bundleLoader = Equinox_BundleHost_getBundleLoader_method.invoke(bundle,new Object[] {});
if (Equinox_BundleLoader_createClassLoader_method == null && bundleLoader != null)
{
Equinox_BundleLoader_createClassLoader_method = bundleLoader.getClass().getClassLoader().loadClass(
"org.eclipse.osgi.internal.loader.BundleLoader").getDeclaredMethod("createClassLoader",new Class[] {});
Equinox_BundleLoader_createClassLoader_method.setAccessible(true);
}
return (ClassLoader)Equinox_BundleLoader_createClassLoader_method.invoke(bundleLoader,new Object[] {});
}
catch (Throwable t)
{
t.printStackTrace();
}
return null;
}
private static Field Felix_BundleImpl_m_modules_field;
private static Field Felix_ModuleImpl_m_classLoader_field;
private static ClassLoader internalGetFelixBundleClassLoader(Bundle bundle)
{
// assume felix:
try
{
// now get the current module from the bundle.
// and return the private field m_classLoader of ModuleImpl
if (Felix_BundleImpl_m_modules_field == null)
{
Felix_BundleImpl_m_modules_field = bundle.getClass().getClassLoader()
.loadClass("org.apache.felix.framework.BundleImpl").getDeclaredField(
"m_modules");
Felix_BundleImpl_m_modules_field.setAccessible(true);
}
Object[] moduleArray = (Object[])Felix_BundleImpl_m_modules_field.get(bundle);
Object currentModuleImpl = moduleArray[moduleArray.length - 1];
if (Felix_ModuleImpl_m_classLoader_field == null && currentModuleImpl != null)
{
Felix_ModuleImpl_m_classLoader_field = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.ModuleImpl").getDeclaredField(
"m_classLoader");
Felix_ModuleImpl_m_classLoader_field.setAccessible(true);
}
// first make sure that the classloader is ready:
// the m_classLoader field must be initialized by the ModuleImpl.getClassLoader() private method.
ClassLoader cl = (ClassLoader)Felix_ModuleImpl_m_classLoader_field.get(currentModuleImpl);
if (cl == null)
{
// looks like it was not ready:
// the m_classLoader field must be initialized by the ModuleImpl.getClassLoader() private method.
// this call will do that.
bundle.loadClass("java.lang.Object");
cl = (ClassLoader)Felix_ModuleImpl_m_classLoader_field.get(currentModuleImpl);
// System.err.println("Got the bundle class loader of felix_: " + cl);
return cl;
}
else
{
// System.err.println("Got the bundle class loader of felix: " + cl);
return cl;
}
}
catch (Throwable t)
{
t.printStackTrace();
}
return null;
}
}

View File

@ -0,0 +1,202 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.boot.utils.internal;
import java.io.File;
import java.lang.reflect.Field;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.zip.ZipFile;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
import org.osgi.framework.Bundle;
/**
* From a bundle to its location on the filesystem. Assumes the bundle is not a jar.
*
* @author hmalphettes
*/
public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
{
// hack to locate the file-system directly from the bundle.
// support equinox, felix and nuxeo's osgi implementations.
// not tested on nuxeo and felix just yet.
// The url nuxeo and felix return is created directly from the File so it should work.
private static Field BUNDLE_ENTRY_FIELD = null;
private static Field FILE_FIELD = null;
private static Field BUNDLE_FILE_FIELD_FOR_DIR_ZIP_BUNDLE_ENTRY = null;// ZipBundleFile inside DirZipBundleEntry
private static Field ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE = null;// ZipFile
/**
* Works with equinox, felix, nuxeo and probably more.
* Not exactly in the spirit of OSGi but quite necessary to support self-contained webapps and other
* situations.
* <p>
* Currently only works with bundles that are not jar.
* </p>
*
* @param bundle
* The bundle
* @return Its installation location as a file.
* @throws Exception
*/
public File getBundleInstallLocation(Bundle bundle) throws Exception
{
// String installedBundles = System.getProperty("osgi.bundles");
// grab the MANIFEST.MF's url
// and then do what it takes.
URL url = bundle.getEntry("/META-INF/MANIFEST.MF");
// System.err.println(url.toString() + " " + url.toURI() + " " + url.getProtocol());
if (url.getProtocol().equals("file"))
{
// some osgi frameworks do use the file protocole directly in some situations
return new File(url.toURI()).getParentFile().getParentFile();
}
else if (url.getProtocol().equals("bundleentry"))
{
// say hello to equinox who has its own protocol.
// we use introspection like there is no tomorrow to get access to the File
URLConnection con = url.openConnection();
if (BUNDLE_ENTRY_FIELD == null)
{
BUNDLE_ENTRY_FIELD = con.getClass().getDeclaredField("bundleEntry");
BUNDLE_ENTRY_FIELD.setAccessible(true);
}
Object bundleEntry = BUNDLE_ENTRY_FIELD.get(con);
if (bundleEntry.getClass().getName().equals("org.eclipse.osgi.baseadaptor.bundlefile.FileBundleEntry"))
{
if (FILE_FIELD == null)
{
FILE_FIELD = bundleEntry.getClass().getDeclaredField("file");
FILE_FIELD.setAccessible(true);
}
File f = (File)FILE_FIELD.get(bundleEntry);
return f.getParentFile().getParentFile();
}
else if (bundleEntry.getClass().getName().equals("org.eclipse.osgi.baseadaptor.bundlefile.ZipBundleEntry"))
{
url = bundle.getEntry("/");
con = url.openConnection();
if (BUNDLE_ENTRY_FIELD == null)
{// this one will be a DirZipBundleEntry
BUNDLE_ENTRY_FIELD = con.getClass().getDeclaredField("bundleEntry");
BUNDLE_ENTRY_FIELD.setAccessible(true);
}
bundleEntry = BUNDLE_ENTRY_FIELD.get(con);
if (BUNDLE_FILE_FIELD_FOR_DIR_ZIP_BUNDLE_ENTRY == null)
{
BUNDLE_FILE_FIELD_FOR_DIR_ZIP_BUNDLE_ENTRY = bundleEntry.getClass().getDeclaredField("bundleFile");
BUNDLE_FILE_FIELD_FOR_DIR_ZIP_BUNDLE_ENTRY.setAccessible(true);
}
Object zipBundleFile = BUNDLE_FILE_FIELD_FOR_DIR_ZIP_BUNDLE_ENTRY.get(bundleEntry);
if (ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE == null)
{
ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE = zipBundleFile.getClass().getDeclaredField("zipFile");
ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE.setAccessible(true);
}
ZipFile zipFile = (ZipFile)ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE.get(zipBundleFile);
return new File(zipFile.getName());
}
else if (bundleEntry.getClass().getName().equals("org.eclipse.osgi.baseadaptor.bundlefile.DirZipBundleEntry"))
{
// that will not happen as we did ask for the manifest not a directory.
}
}
else if ("bundle".equals(url.getProtocol()))
{
// observed this on felix-2.0.0
String location = bundle.getLocation();
if (location.startsWith("file:/"))
{
URI uri = new URI(bundle.getLocation());
return new File(uri);
}
}
return null;
}
/**
* Locate a file inside a bundle.
*
* @param bundle
* @param path
* @return
* @throws Exception
*/
public File getFileInBundle(Bundle bundle, String path) throws Exception
{
if (path != null && path.length() > 0 && path.charAt(0) == '/')
{
path = path.substring(1);
}
File bundleInstall = getBundleInstallLocation(bundle);
File webapp = path != null && path.length() != 0?new File(bundleInstall,path):bundleInstall;
if (!webapp.exists())
{
throw new IllegalArgumentException("Unable to locate " + path + " inside " + bundle.getSymbolicName() + " ("
+ (bundleInstall != null?bundleInstall.getAbsolutePath():" no_bundle_location ") + ")");
}
return webapp;
}
/**
* If the bundle is a jar, returns the jar. If the bundle is a folder, look inside it and search for jars that it returns.
* <p>
* Good enough for our purpose (TldLocationsCache when it scans for tld files inside jars alone. In fact we only support the second situation for
* development purpose where the bundle was imported in pde and the classes kept in a jar.
* </p>
*
* @param bundle
* @return The jar(s) file that is either the bundle itself, either the jars embedded inside it.
*/
public File[] locateJarsInsideBundle(Bundle bundle) throws Exception
{
File jasperLocation = getBundleInstallLocation(bundle);
if (jasperLocation.isDirectory())
{
// try to find the jar files inside this folder
ArrayList<File> urls = new ArrayList<File>();
for (File f : jasperLocation.listFiles())
{
if (f.getName().endsWith(".jar") && f.isFile())
{
urls.add(f);
}
else if (f.isDirectory() && f.getName().equals("lib"))
{
for (File f2 : jasperLocation.listFiles())
{
if (f2.getName().endsWith(".jar") && f2.isFile())
{
urls.add(f2);
}
}
}
}
return urls.toArray(new File[urls.size()]);
}
else
{
return new File[]
{ jasperLocation };
}
}
}

View File

@ -0,0 +1,12 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: OSGi HttpService provided by equinox HttpServiceServlet deployed on jetty
Bundle-SymbolicName: org.eclipse.jetty.osgi.httpservice
Bundle-Version: 7.0.1.qualifier
Bundle-Vendor: Intalio Inc
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Import-Package: javax.servlet;version="2.5.0",
javax.servlet.http;version="2.5.0",
org.osgi.service.http;version="1.2.0",
org.eclipse.equinox.http.servlet
Jetty-ContextFilePath: contexts/httpservice.xml

View File

@ -0,0 +1,4 @@
source.. = src/main/java/
output.. = target/classes/
bin.includes = META-INF/,\
.

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<!--
// ========================================================================
// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
//
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
-->
<Configure class="org.eclipse.jetty.servlet.ServletContextHandler">
<!-- this servlet provides the OSGi HTTP Service once it is initialized -->
<Call name="addServlet">
<Arg>org.eclipse.jetty.osgi.httpservice.HttpServiceServletX</Arg>
<Arg>/*</Arg>
</Call>
</Configure>

View File

@ -0,0 +1,28 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.osgi.httpservice;
import org.eclipse.equinox.http.servlet.HttpServiceServlet;
/**
* Once this servlet is initialized, it provides the OSGi HttpService.
* Compliments of equinox. Currently has no added value.
*/
public class HttpServiceServletX extends HttpServiceServlet
{
/**
*
*/
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,16 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Eclipse PDE Run Configuration
Bundle-SymbolicName: org.eclipse.jetty.osgi.pde.launch;singleton:=true
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: org.eclipse.jetty.osgi.pde.launch.JettyOSGiPDEPlugin
Bundle-Vendor: Intalio Inc
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
org.eclipse.debug.core;bundle-version="3.5.0",
org.eclipse.pde.ui;bundle-version="3.5.0",
org.eclipse.debug.ui;bundle-version="3.5.0",
org.eclipse.core.variables;bundle-version="3.2.200",
org.eclipse.jdt.debug.ui;bundle-version="3.4.1"
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Bundle-ActivationPolicy: lazy

View File

@ -0,0 +1,5 @@
source.. = src/main/java/
output.. = target/classes/
bin.includes = META-INF/,\
.,\
plugin.xml

Binary file not shown.

After

Width:  |  Height:  |  Size: 815 B

View File

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<!--
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
//
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
-->
<plugin>
<extension
point="org.eclipse.debug.core.launchConfigurationTypes">
<launchConfigurationType
delegate="org.eclipse.jetty.osgi.pde.launch.ui.JettyEquinoxLaunchConfiguration"
delegateDescription="Launch Jetty in OSGi"
delegateName="%PDELaunchDelegate.name"
id="org.eclipse.jetty.osgi.pde.launch.ui.jettyosgilaunch"
migrationDelegate="org.eclipse.pde.internal.ui.launcher.OSGiMigrationDelegate"
modes="run, debug"
name="Launch Jetty in OSGi"
sourceLocatorId="org.eclipse.pde.ui.launcher.PDESourceLookupDirector"
sourcePathComputerId="org.eclipse.jdt.launching.sourceLookup.javaSourcePathComputer">
</launchConfigurationType>
</extension>
<extension
point="org.eclipse.debug.ui.launchConfigurationTypeImages">
<launchConfigurationTypeImage
icon="$nl$/icons/jetty.png"
configTypeID="org.eclipse.jetty.osgi.pde.launch.ui.jettyosgilaunch"
id="org.eclipse.jetty.osgi.pde.launch.jettyLaunchImage">
</launchConfigurationTypeImage>
</extension>
<extension
point="org.eclipse.debug.ui.launchShortcuts">
<shortcut
label="Jetty on OSGi"
icon="$nl$/icons/jetty.png"
modes="run, debug"
class="org.eclipse.jetty.osgi.pde.launch.ui.JettyLaunchShortcut"
id="org.eclipse.jetty.osgi.pde.launch.runjetty">
<contextualLaunch>
<enablement>
<with variable="selection">
<count value="1"/>
<iterate>
<and>
<instanceof value="org.eclipse.core.runtime.IAdaptable"/>
<test property="org.eclipse.debug.ui.projectNature" value="org.eclipse.pde.PluginNature"/>
<or>
<adapt type="org.eclipse.core.resources.IProject"/>
<test property="org.eclipse.debug.ui.matchesPattern" value="MANIFEST.MF"/>
</or>
</and>
</iterate>
</with>
</enablement>
</contextualLaunch>
<configurationType
id="org.eclipse.jetty.osgi.pde.launch.ui.jettyosgilaunch">
</configurationType>
<description
description="Lauch jetty in OSGi and deploy the OSGi webapps"
mode="run">
</description>
<description
description="Debug jetty in OSGi and the OSGi webapps"
mode="debug">
</description>
</shortcut>
</extension>
<extension
point="org.eclipse.debug.ui.launchConfigurationTabGroups">
<launchConfigurationTabGroup
type="org.eclipse.jetty.osgi.pde.launch.ui.jettyosgilaunch"
class="org.eclipse.jetty.osgi.pde.launch.ui.JettyOSGiLauncherTabGroup"
id="org.eclipse.jetty.osgi.pde.launch.ui.EquinoxLauncherTabGroup">
<launchMode
description="Create a configuration to launch Jetty in OSGi in debug mode"
perspective="org.eclipse.debug.ui.DebugPerspective"
mode="debug">
</launchMode>
<launchMode
description="Create a configuration to launch Jetty in OSGi in run mode"
mode="run">
</launchMode>
</launchConfigurationTabGroup>
</extension>
</plugin>

View File

@ -0,0 +1,28 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.pde.launch;
/**
* Configuration constants.
*/
public class JettyConfigurationConstants
{
private static final String PLUGIN_ID = JettyOSGiPDEPlugin.PLUGIN_ID;
/** Points to the jetty home folder */
public static final String ATTR_JETTY_HOME = PLUGIN_ID + ".jettyhome";
public static final String JETTY_HOME_DEFAULT = "${workspace_loc}/jettyhome";
}

View File

@ -0,0 +1,45 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.pde.launch;
import org.eclipse.osgi.util.NLS;
/**
* NLS
*/
public class JettyLauncherMessages extends NLS
{
private static final String BUNDLE_NAME = "org.eclipse.jetty.osgi.pde.launch.JettyLauncherMessages";//$NON-NLS-1$
public static String JettyConfigurationLaunchTab_JettyConfigurationTitle;
public static String JettyConfigurationLaunchTab_VariablesButtonLabel;
public static String JettyXmlBlock_JettyConfigurationBlockTitle;
public static String JettyXmlBlock_JettyConfigurationBlockLabel;
public static String JettyXmlBlock_VariablesButtonLabel;
public static String JettyXmlEditDialog_Cancel;
public static String JettyXmlEditDialog_OK;
public static String JettyXmlEditDialog_Apply;
public static String JettyXmlEditDialog_Edit_jetty_xml;
public static String JettyXmlEditDialog_Edit_jetty_xml_title;
static {
// load message values from bundle file
NLS.initializeMessages(BUNDLE_NAME, JettyLauncherMessages.class);
}
}

View File

@ -0,0 +1,24 @@
# ========================================================================
# Copyright (c) 2009 Intalio, Inc.
# ------------------------------------------------------------------------
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# and Apache License v2.0 which accompanies this distribution.
# The Eclipse Public License is available at
# http://www.eclipse.org/legal/epl-v10.html
# The Apache License v2.0 is available at
# http://www.opensource.org/licenses/apache2.0.php
# Contributors:
# Hugues Malphettes - initial API and implementation
# You may elect to redistribute this code under either of these licenses.
# ========================================================================
JettyConfigurationLaunchTab_JettyConfigurationTitle=Jetty &Configuration
JettyConfigurationLaunchTab_VariablesButtonLabel=Var&iables...
JettyXmlBlock_JettyConfigurationBlockTitle=jetty.xml configuration file:
JettyXmlBlock_JettyConfigurationBlockLabel=jetty.xml &configuration file:
JettyXmlBlock_VariablesButtonLabel=Variable&s
JettyXmlEditDialog_Cancel=Cancel
JettyXmlEditDialog_OK=OK
JettyXmlEditDialog_Apply=Apply
JettyXmlEditDialog_Edit_jetty_xml_title=Edit jetty.xml
JettyXmlEditDialog_Edit_jetty_xml=Edit jetty.xml in ${0}

View File

@ -0,0 +1,71 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.pde.launch;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
/**
* The activator class controls the plug-in life cycle
*/
public class JettyOSGiPDEPlugin extends AbstractUIPlugin
{
// The plug-in ID
public static final String PLUGIN_ID = "org.eclipse.jetty.osgi.pde.core";
// The shared instance
private static JettyOSGiPDEPlugin plugin;
/**
* The constructor
*/
public JettyOSGiPDEPlugin()
{
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext context) throws Exception
{
super.start(context);
plugin = this;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception
{
plugin = null;
super.stop(context);
}
/**
* Returns the shared instance
*
* @return the shared instance
*/
public static JettyOSGiPDEPlugin getDefault()
{
return plugin;
}
}

View File

@ -0,0 +1,471 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.pde.launch.internal;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URI;
import java.nio.channels.FileChannel;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.variables.IStringVariableManager;
import org.eclipse.core.variables.VariablesPlugin;
import org.osgi.framework.Bundle;
/**
* Utility methods related to jetty home and jetty.xml.
* Default will be something like this:
* ${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/Launch Jetty in OSGi
*/
public class JettyHomeHelper
{
/**
* Helper
* @return The bundle that is in charge of starting jetty in OSGi.
*/
private static Bundle getJettyOSGiBootBundle()
{
return Platform.getBundle("org.eclipse.jetty.osgi.boot");
}
private static String resolveVariables(String target) {
IStringVariableManager manager = VariablesPlugin.getDefault().getStringVariableManager();
try
{
return manager.performStringSubstitution(target, false);
}
catch (CoreException e)
{
}
return null;
}
/**
* Resolves strings that start with &quot;${workspace_loc:&quot;
* or &quot;${workspace}&quot;
* Useful as the default configuration area used by pde is:
* ${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/${name_of_configuration}
* @see IStringVariableManager
* @see org.eclipse.pde.internal.ui.launcher.ConfigurationTemplateBlock
* @return The container
*/
public static IContainer getContainerFromWorkspace(String path)
{
// /.../theworkspace/.metadata/.plugins/org.eclipse.pde.core/Launch Jetty in OSGi/jettyhome
if (path == null || path.trim().length() == 0)
{
return null;
}
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
if (path.startsWith("${workspace_loc:"))
{
path = resolveVariables(path);
return root.getContainerForLocation(new Path(path).makeAbsolute());
}
else if (path.startsWith("${workspace_loc}"))
{
path = path.substring("${workspace_loc}".length());
path = resolveVariables(path);
IFolder f = root.getFolder(new Path(path).makeAbsolute());
if (f.getRawLocation() == null) {
IContainer c = root.getContainerForLocation(new Path(path).makeAbsolute());
if (c != null) {
return c;
} else {
return null;
}
}
}
IResource res = root.findMember(path);
if (res instanceof IContainer)
{
return (IContainer) res;
}
return null;
}
/**
* Resolves strings and try to make it a file in the filesystem.
* @see IStringVariableManager
* @see org.eclipse.pde.internal.ui.launcher.ConfigurationTemplateBlock
* @return The container
*/
public static File getFileOutsideOfWorkspace(String path)
{
if (path == null || path.trim().length() == 0)
{
return null;
}
return new File(resolveVariables(path));
}
/**
* The current content of jettyXml
*/
public static String getCurrentJettyXml(String jettyHomePath, boolean returnNullIfJettyXmlIsNull)
{
IContainer container = JettyHomeHelper.getContainerFromWorkspace(jettyHomePath);
if (container != null)
{
IFile jettyXml = container.getFile(new Path("jettyhome/etc/jetty.xml"));
if (!jettyXml.exists()) {
//does not exist at this point:
//just read the one in the bundle directly.
return returnNullIfJettyXmlIsNull ? null : JettyHomeHelper.getJettyXmlInsideBootBundle();
} else {
//return the one that exists already.
return JettyHomeHelper.loadIFileAsString(jettyXml);
}
}
else
{
File configArea = JettyHomeHelper.getFileOutsideOfWorkspace(jettyHomePath);
File jettyXml = new File(configArea, "jettyhome/etc/jetty.xml");
if (jettyXml.exists()) {
return JettyHomeHelper.loadFileAsString(jettyXml);
} else {
//does not exist at this point:
//just read the one in the bundle directly.
return returnNullIfJettyXmlIsNull ? null : JettyHomeHelper.getJettyXmlInsideBootBundle();
}
}
}
/**
* @return The content of jetty.xml inside the boot bundle.
*/
public static String getJettyXmlInsideBootBundle()
{
Bundle b = getJettyOSGiBootBundle();
try
{
InputStream is = b.getEntry("/jettyhome/etc/jetty.xml").openStream();
return loadInputAsString(is);
}
catch (IOException e)
{
e.printStackTrace();
}
return null;
}
/**
* Something really straight forward to read the content of the file.
* It is just jetty.xml: no need to be really fast and optimized here.
*/
public static String loadFileAsString(File jettyXml)
{
try
{
return loadInputAsString(new FileInputStream(jettyXml));
}
catch (IOException e)
{
e.printStackTrace();
}
return null;
}
/**
* Something really straight forward to read the content of the file.
* It is just jetty.xml: no need to be really fast and optimized here.
*/
public static String loadIFileAsString(IFile jettyXml)
{
try
{
return loadInputAsString(jettyXml.getContents());
}
catch (CoreException e)
{
e.printStackTrace();
}
return null;
}
/**
* Something really straight forward to read the content of the file.
* It is just jetty.xml: no need to be really fast and optimized here.
*/
public static String loadInputAsString(InputStream is)
{
StringBuilder sb = new StringBuilder();
try
{
BufferedReader reader = new BufferedReader(new InputStreamReader(is,"UTF-8")); //$NON-NLS-1$
String newline = System.getProperty("line.separator"); //$NON-NLS-1$
String line = null;
while ((line = reader.readLine()) != null)
{
sb.append(line + newline);
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
try
{
is.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
return sb.toString();
}
public static File resolveJettyHome(String jettyHomeInConfig) {
IContainer container = JettyHomeHelper.getContainerFromWorkspace(jettyHomeInConfig);
if (container != null)
{
URI rawURI = container.getRawLocationURI();
if (rawURI != null) {
//it is null when the folder is not inside a project.
return new File(rawURI);
}
}
return JettyHomeHelper.getFileOutsideOfWorkspace(jettyHomeInConfig);
}
/**
* Look for the jettyhome folder.
* If empty or it does not exist, extract the default one from the boot.
*
*
* @param jettyXml custom content for jetty.xml or null if we keep the default one.
* @param jettyHomePath path to jettyhome as set by the user.
*/
public static void setupJettyHomeAndJettyXML(String jettyXml, String jettyHomePath,
boolean doNothingIfJettyHomeExists)
throws IOException
{
File jettyhome = resolveJettyHome(jettyHomePath);
if (jettyhome == null)
{//we probably have a problem now.
throw new IllegalArgumentException(
"Unable to resolve jettyhome " + jettyHomePath);
}
if (!jettyhome.exists())
{
//does not exist at this point: extract the default one:
installDefaultJettyHome(jettyhome);
}
else if (doNothingIfJettyHomeExists)
{
return;
}
//check jetty.xml exists.
File jettyXmlFile = new File(jettyhome, "etc/jetty.xml");
if (!jettyXmlFile.exists())
{//we probably have a problem now.
throw new IllegalArgumentException(
"The jetty configuration file must exist: '"
+ jettyXmlFile.getAbsolutePath());
}
if (jettyXml != null) {
//override the current jettyxml:
FileOutputStream out = null;
try
{
out = new FileOutputStream(jettyXmlFile);
OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8");
writer.append(jettyXml);
}
finally
{
if (out != null) try { out.close(); } catch (IOException ioee) {}
}
}
}
/**
* Actually creates the jettyhome folder template in the location set
* for the user.
* Currently unzips the jettyhome folder located in the
* org.eclipse.jetty.osgi.boot bundle.
*/
public static void installDefaultJettyHome(File jettyhomeFolder) throws IOException
{
jettyhomeFolder.mkdirs();
Bundle bootBundle = getJettyOSGiBootBundle();
File bootBundleFile = FileLocator.getBundleFile(bootBundle);
if (bootBundleFile.getName().endsWith(".jar"))
{
//unzip it.
unzipJettyHomeIntoDirectory(bootBundleFile, jettyhomeFolder);
}
else
{
//copy the folders.
copyDirectory(new File(bootBundleFile, "jettyhome"), jettyhomeFolder);
}
}
/**
* @param zipFile
* The current jar file for this bundle. contains an archive of
* the default jettyhome
* @param parentOfMagicJettyHome
* The folder inside which jettyhome is created.
*/
private static void unzipJettyHomeIntoDirectory(File thisbundlejar,
File parentOfMagicJettyHome) throws IOException
{
ZipFile zipFile = null;
try
{
zipFile = new ZipFile(thisbundlejar);
Enumeration<? extends ZipEntry> files = zipFile.entries();
File f = null;
FileOutputStream fos = null;
while (files.hasMoreElements())
{
try
{
ZipEntry entry = files.nextElement();
String entryName = entry.getName();
if (!entryName.startsWith("jettyhome"))
{
continue;
}
InputStream eis = zipFile.getInputStream(entry);
byte[] buffer = new byte[1024];
int bytesRead = 0;
f = new File(parentOfMagicJettyHome,entry.getName());
if (entry.isDirectory())
{
f.mkdirs();
}
else
{
f.getParentFile().mkdirs();
f.createNewFile();
fos = new FileOutputStream(f);
while ((bytesRead = eis.read(buffer)) != -1)
{
fos.write(buffer,0,bytesRead);
}
}
}
catch (IOException e)
{
e.printStackTrace();
continue;
}
finally
{
if (fos != null)
{
try
{
fos.close();
}
catch (IOException e)
{
}
fos = null;
}
}
}
}
finally
{
if (zipFile != null) try { zipFile.close(); } catch (Throwable t) {}
}
}
private static void copyDirectory(File sourceFile, File destFile) throws IOException
{
if (sourceFile.isDirectory())
{
if (!destFile.exists())
{
destFile.mkdir();
}
String files[] = sourceFile.list();
for (int i = 0; i < files.length; i++)
{
copyDirectory(new File(sourceFile,files[i]),new File(destFile,files[i]));
}
}
else
{
if (!sourceFile.exists())
{
//humf
}
else
{
copyFile(sourceFile,destFile);
}
}
}
private static void copyFile(File sourceFile, File destFile) throws IOException
{
if (!destFile.exists())
{
destFile.createNewFile();
}
FileChannel source = null;
FileChannel destination = null;
try
{
source = new FileInputStream(sourceFile).getChannel();
destination = new FileOutputStream(destFile).getChannel();
destination.transferFrom(source,0,source.size());
}
finally
{
if (source != null) { source.close(); }
if (destination != null) { destination.close(); }
}
}
}

View File

@ -0,0 +1,29 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.pde.launch.ui;
/**
* Object that can read the value of the osgi.config.area property that will be
* used when the OSGi app is launched.
*/
public interface IConfigurationAreaSettingHolder
{
/**
* @return the string entered in the settings tab that defines the
* value o osgi.config.area.
*/
public String getConfigurationAreaLocation();
}

View File

@ -0,0 +1,124 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.pde.launch.ui;
import java.io.File;
import java.io.IOException;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.jetty.osgi.pde.launch.JettyConfigurationConstants;
import org.eclipse.jetty.osgi.pde.launch.JettyOSGiPDEPlugin;
import org.eclipse.jetty.osgi.pde.launch.internal.JettyHomeHelper;
import org.eclipse.pde.internal.ui.launcher.LaunchConfigurationHelper;
import org.eclipse.pde.ui.launcher.EquinoxLaunchConfiguration;
import org.eclipse.pde.ui.launcher.IPDELauncherConstants;
/**
*
*/
public class JettyEquinoxLaunchConfiguration extends EquinoxLaunchConfiguration
{
/** The configuration type as declared in the extension point's plugin.xml */
public static final String ID = "org.eclipse.jetty.osgi.pde.launch.ui.jettyosgilaunch";
@Override
protected void preLaunchCheck(ILaunchConfiguration configuration, ILaunch launch, IProgressMonitor monitor) throws CoreException
{
if (!configuration.getAttribute(IPDELauncherConstants.DOCLEAR, false))
{
super.preLaunchCheck(configuration,launch,monitor);
//make sure jettyhome exists and set it up if it does not:
File jettyHome = resolveJettyHome(configuration);
if (jettyHome != null && !jettyHome.exists())
{
try
{
JettyHomeHelper.setupJettyHomeAndJettyXML(null, jettyHome.getAbsolutePath(), true);
}
catch (IOException e)
{
throw new CoreException(new Status(IStatus.ERROR,
JettyOSGiPDEPlugin.PLUGIN_ID,"Unable to setup jettyhome", e));
}
}
return;//nothing else to do.
}
//this will wipe the workspace if it was configured that way.
//it means we must setup jettyhome and jettyxml immediately after
//if indeed it was wiped:
String jettyHomePath = resolveJettyHome(configuration).getAbsolutePath();
String jettyXml = JettyHomeHelper.getCurrentJettyXml(jettyHomePath, true);
super.preLaunchCheck(configuration,launch,monitor);
try
{
JettyHomeHelper.setupJettyHomeAndJettyXML(jettyXml, jettyHomePath, true);
}
catch (IOException e)
{
throw new CoreException(new Status(IStatus.ERROR,
JettyOSGiPDEPlugin.PLUGIN_ID,"Unable to setup jettyhome", e));
}
}
/**
* Append -Djetty.home
*/
@Override
public String[] getVMArguments(ILaunchConfiguration configuration) throws CoreException
{
String[] args = super.getVMArguments(configuration);
for (int i = 0; i < args.length ;i++) {
String arg = args[i];
if (arg.startsWith("-Djetty.home=")) {
//overridden by the arg nothing to change (?)
return args;
}
}
String jettyHomePath = configuration.getAttribute(JettyConfigurationConstants.ATTR_JETTY_HOME, "");
File jettyHome = resolveJettyHome(configuration);
if (jettyHome == null || !jettyHome.exists())
{
//err?
System.err.println("could not resolve jettyhome; "
+ jettyHomePath + " -> " + jettyHome);
return args;
}
String[] newArgs = new String[args.length+1];
System.arraycopy(args, 0, newArgs, 0, args.length);
newArgs[args.length] = "-Djetty.home=\""+jettyHome.getAbsolutePath()+"\"";
return newArgs;
}
private File resolveJettyHome(ILaunchConfiguration configuration) throws CoreException
{
String jettyHomePath = configuration.getAttribute(JettyConfigurationConstants.ATTR_JETTY_HOME, "");
if (jettyHomePath == null || jettyHomePath.length() == 0)
{
File configArea = LaunchConfigurationHelper.getConfigurationArea(configuration);
return new File(configArea, "jettyhome");
}
else
{
return JettyHomeHelper.resolveJettyHome(jettyHomePath);
}
}
}

View File

@ -0,0 +1,89 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
package org.eclipse.jetty.osgi.pde.launch.ui;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.pde.ui.launcher.AbstractLaunchShortcut;
import org.eclipse.pde.ui.launcher.IPDELauncherConstants;
import org.eclipse.ui.IEditorPart;
/**
* Shortcut to launch Jetty on osgi.
*/
public class JettyLaunchShortcut extends AbstractLaunchShortcut
{
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.ui.ILaunchShortcut#launch(org.eclipse.jface.viewers.ISelection, java.lang.String)
*/
public void launch(ISelection selection, String mode)
{
launch(mode);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.ui.ILaunchShortcut#launch(org.eclipse.ui.IEditorPart, java.lang.String)
*/
public void launch(IEditorPart editor, String mode)
{
launch(mode);
}
/**
* Returns the launch configuration type name.
*
* @return the launch configuration type name
*/
protected String getLaunchConfigurationTypeName()
{
return JettyEquinoxLaunchConfiguration.ID;
}
/**
* Initialize launch attributes on the new launch configuration. Must be overridden by subclasses.
*
* @param wc
* the launch configuration working copy to be initialize
*
* @see IPDELauncherConstants
*/
protected void initializeConfiguration(ILaunchConfigurationWorkingCopy wc)
{
JettyOSGiLaunchConfigurationInitializer confInitializer = new JettyOSGiLaunchConfigurationInitializer();
confInitializer.initialize(wc);
}
/**
* Determines whether a given launch configuration is a good match given the
* current application or framework being launched. This method must be overridden
* by subclasses. Its purpose is to add criteria on what makes a good match or not.
*
* @param configuration
* the launch configuration being evaluated
* @return <code>true</code> if the launch configuration is a good match
* for the application or framework being launched,
* <code>false</code> otherwise.
*/
protected boolean isGoodMatch(ILaunchConfiguration configuration)
{
return true;
}
}

View File

@ -0,0 +1,203 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.pde.launch.ui;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.osgi.service.resolver.ExportPackageDescription;
import org.eclipse.pde.core.plugin.IPluginModelBase;
import org.eclipse.pde.core.plugin.PluginRegistry;
import org.eclipse.pde.internal.ui.launcher.BundleLauncherHelper;
import org.eclipse.pde.internal.ui.launcher.EquinoxInitializer;
import org.eclipse.pde.ui.launcher.IPDELauncherConstants;
/**
* In charge of selecting the proper default bundles to load and to make sure
* that the jetty.osgi.boot bundle will in fact start.
* <p>
* The default behavior of OSGi run configuration is to select everything.
* This is overwhelming for the web-app developer.
* This run configuration initializer will select the minimum set of plugins to run jetty.
* </p>
*/
public class JettyOSGiLaunchConfigurationInitializer extends EquinoxInitializer
{
/** well known bundles that jetty depends on, often optional dependency. */
private static final Set<String> BUNDLE_DEPENDENCIES = new HashSet<String>();
/** well known bundles required to support headles jdt */
private static final Set<String> JDT_HEADLESS_DEPENDENCIES = new HashSet<String>();
private static final Set<String> ALL_BUNDLE_DEPS = new HashSet<String>();
/** we don't know the bundle but if we find a bundle that exports this package */
private static final Set<String> PACKAGES_DEPENDENCIES = new HashSet<String>();
private static final String JETTY_BUNDLES_PREFIX = "org.eclipse.jetty.";
private static final String JETTY_JSP_BUNDLES_PREFIX = "org.mortbay.jetty.jsp-";
static {
BUNDLE_DEPENDENCIES.add("javax.servlet");
BUNDLE_DEPENDENCIES.add("org.eclipse.osgi");
BUNDLE_DEPENDENCIES.add("org.eclipse.osgi.services");
BUNDLE_DEPENDENCIES.add("org.objectweb.asm");
PACKAGES_DEPENDENCIES.add("javax.mail");
PACKAGES_DEPENDENCIES.add("javax.transaction");
PACKAGES_DEPENDENCIES.add("javax.activation");
PACKAGES_DEPENDENCIES.add("javax.annotation");
//now add the headless jdt:
//no more ecj: we use jdt.core instead that contains ecj.
// BUNDLE_DEPENDENCIES.add("org.eclipse.jdt.core.compiler.batch");
JDT_HEADLESS_DEPENDENCIES.add("org.eclipse.core.commands");
JDT_HEADLESS_DEPENDENCIES.add("org.eclipse.core.contenttype");
JDT_HEADLESS_DEPENDENCIES.add("org.eclipse.core.expressions");
JDT_HEADLESS_DEPENDENCIES.add("org.eclipse.core.filessytem");
JDT_HEADLESS_DEPENDENCIES.add("org.eclipse.core.jobs");
JDT_HEADLESS_DEPENDENCIES.add("org.eclipse.core.resources");
JDT_HEADLESS_DEPENDENCIES.add("org.eclipse.core.runtime");
JDT_HEADLESS_DEPENDENCIES.add("org.eclipse.core.variables");
JDT_HEADLESS_DEPENDENCIES.add("org.eclipse.debug.core");
JDT_HEADLESS_DEPENDENCIES.add("org.eclipse.equinox.app");
JDT_HEADLESS_DEPENDENCIES.add("org.eclipse.equinox.common");
JDT_HEADLESS_DEPENDENCIES.add("org.eclipse.equinox.preferences");
JDT_HEADLESS_DEPENDENCIES.add("org.eclipse.equinox.registry");
JDT_HEADLESS_DEPENDENCIES.add("org.eclipse.equinox.app");
JDT_HEADLESS_DEPENDENCIES.add("org.eclipse.jdt.core");
JDT_HEADLESS_DEPENDENCIES.add("org.eclipse.jdt.debug");
JDT_HEADLESS_DEPENDENCIES.add("org.eclipse.jdt.launching");
JDT_HEADLESS_DEPENDENCIES.add("org.eclipse.text");
ALL_BUNDLE_DEPS.addAll(JDT_HEADLESS_DEPENDENCIES);
ALL_BUNDLE_DEPS.addAll(BUNDLE_DEPENDENCIES);
}
/**
* Override the default behavior which consists of selecting every bundle.
* Here we select only the jetty and jdt-headless bundles from the platform
* By default we continue to select all the bundles located in the workspace.
*
* @param configuration the launch configuration
*/
@Override
protected void initializeBundleState(ILaunchConfigurationWorkingCopy configuration)
{
List<IPluginModelBase> bundlesInPlatform = new ArrayList<IPluginModelBase>();
List<IPluginModelBase> bundlesInWorkspace = new ArrayList<IPluginModelBase>();
selectBundles(bundlesInPlatform, bundlesInWorkspace);
configuration.setAttribute(IPDELauncherConstants.WORKSPACE_BUNDLES, createBundleList(bundlesInWorkspace));
configuration.setAttribute(IPDELauncherConstants.TARGET_BUNDLES, createBundleList(bundlesInPlatform));
configuration.setAttribute(IPDELauncherConstants.AUTOMATIC_ADD, true);
}
/**
* @return The list of bundles to install along with their start level in the format expected by
* equinox for the config.ini file. For example:
* <code>osgi.bundles=org.eclipse.equinox.common@2:start, org.eclipse.update.configurator@3:start</code>
*
* (As documented here: http://www.eclipse.org/equinox/documents/quickstart.php)
*/
private String createBundleList(List<IPluginModelBase> bundlesInPlatform)
{
StringBuilder bundlesInPlatformString = new StringBuilder();
String sep = "";
for (IPluginModelBase bundleModel : bundlesInPlatform)
{
String id = bundleModel.getPluginBase().getId();
bundlesInPlatformString.append(sep
+ BundleLauncherHelper.writeBundleEntry(bundleModel,
getStartLevel(id), getAutoStart(id)));
sep = ",";
}
return bundlesInPlatformString.toString();
}
/**
* This is where we are doing something else than the default OSGi launch configuration initializer.
* We select only the jetty plugins, their dependencies and the jdt-headless plugins
* if we want to launch the ability to debug the java projects too.
*
* @param bundlesInPlatformCollector Where the bundles that belong to the platform are collected.
* @param bundlesInWorkspaceCollector Where the bundles that belong to the workspace are collected.
*/
private void selectBundles(List<IPluginModelBase> bundlesInPlatformCollector,
List<IPluginModelBase> bundlesInWorkspaceCollector)
{
for (IPluginModelBase pluginModel : PluginRegistry.getActiveModels())
{
String symbName = pluginModel.getBundleDescription().getSymbolicName();
if (pluginModel.getUnderlyingResource() != null)
{
//all bundles in the workspace are added by default.
bundlesInWorkspaceCollector.add(pluginModel);
continue;
}
if (symbName.startsWith(JETTY_BUNDLES_PREFIX))
{
if (symbName.startsWith("org.eclipse.jetty.osgi.pde"))
{
// don't select the SDK PDE plugins for running jetty!
continue;
}
}
else if (symbName.startsWith(JETTY_JSP_BUNDLES_PREFIX))
{
//let's add them.
bundlesInPlatformCollector.add(pluginModel);
}
else if (!ALL_BUNDLE_DEPS.contains(symbName))
{
ExportPackageDescription[] exPacks =
pluginModel.getBundleDescription().getExportPackages();
for (int j = 0; j < exPacks.length; j++)
{
ExportPackageDescription xp = exPacks[j];
if (PACKAGES_DEPENDENCIES.contains(xp.getName()))
{
bundlesInPlatformCollector.add(pluginModel);
break;
}
}
}
}
}
/**
* Override the default behavior: we need to make sure that
* org.eclipse.jetty.osgi.boot has its autostart level set to 'true'
*/
@Override
protected String getAutoStart(String bundleID)
{
if (bundleID.equals("org.eclipse.jetty.osgi.boot"))
{
return Boolean.TRUE.toString();
}
return super.getAutoStart(bundleID);
}
}

View File

@ -0,0 +1,137 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.pde.launch.ui;
import java.lang.reflect.Field;
import org.eclipse.debug.ui.AbstractLaunchConfigurationTabGroup;
import org.eclipse.debug.ui.ILaunchConfigurationDialog;
import org.eclipse.debug.ui.ILaunchConfigurationTab;
import org.eclipse.jetty.osgi.pde.launch.ui.tabs.JettyConfigurationLaunchTab;
import org.eclipse.pde.ui.launcher.OSGiLauncherTabGroup;
import org.eclipse.pde.ui.launcher.OSGiSettingsTab;
/**
* Customizes the OSGi configuration UI.
* <p>
* Make sure that new default configurations select all the jetty bundles
* and deselect the rest of the platform.
* </p>
* <p>
* Insert a new tab for the configuration of jetty home and the ability to edit
* jetty.xml
* </p>
*/
public class JettyOSGiLauncherTabGroup extends AbstractLaunchConfigurationTabGroup
implements IConfigurationAreaSettingHolder
{
/**
* Use the same tabs than the OSGi lauch.
* Add one first tab to give access to the jetty configuration.
* For now we will simply display the jetty.xml file in a text editor.
*/
public void createTabs(ILaunchConfigurationDialog dialog, String mode)
{
ILaunchConfigurationTab[] tabs = createOSGiLaunchTabs(dialog, mode);
ILaunchConfigurationTab[] newtabs = new ILaunchConfigurationTab[tabs.length+1];
newtabs[0] = new JettyConfigurationLaunchTab(this);
System.arraycopy(tabs, 0, newtabs, 1, tabs.length);
super.setTabs(newtabs);
}
/**
* @param dialog
* @param mode
* @return The tabs created for an OSGi Launch
*/
private ILaunchConfigurationTab[] createOSGiLaunchTabs(ILaunchConfigurationDialog dialog, String mode)
{
OSGiLauncherTabGroup osgiTabsFactory = new OSGiLauncherTabGroup();
osgiTabsFactory.createTabs(dialog, mode);
return osgiTabsFactory.getTabs();
}
/**
* Helper method to read the setting "Configuration Area" in the Settings tab
* that will become the folder pointed by the system property osgi.config.area
* when the app is run.
* <p>
* Painful to access it.
* </p>
*/
public String getConfigurationAreaLocation()
{
OSGiSettingsTab settingsTab = null;
for (ILaunchConfigurationTab t : getTabs())
{
if (t instanceof OSGiSettingsTab) {
settingsTab = (OSGiSettingsTab)t;
break;
}
}
if (settingsTab == null)
{
return null;
}
//OSGisettingsTab contains org.eclipse.pde.internal.ui.launcher.ConfigurationAreaBlock
//it is a private field called "fConfigurationBlock"
//that object contains the private string "fLastEnteredConfigArea"
//which is what we want.
//we must access it from there as we need the value "live"
return getfLastEnteredConfigArea(getfConfigurationBlock(settingsTab));
}
//introspection tricks..
private static Field fConfigurationBlock;
private static Field fLastEnteredConfigArea;
private static synchronized Object getfConfigurationBlock(OSGiSettingsTab settingsTab)
{
try
{
if (fConfigurationBlock == null)
{
fConfigurationBlock = OSGiSettingsTab.class.getDeclaredField("fConfigurationBlock");
fConfigurationBlock.setAccessible(true);
}
return fConfigurationBlock.get(settingsTab);
}
catch (Throwable t)
{
t.printStackTrace();
}
return null;
}
private static synchronized String getfLastEnteredConfigArea(Object configurationBlock)
{
try
{
if (fLastEnteredConfigArea == null)
{
fLastEnteredConfigArea = configurationBlock.getClass().getDeclaredField("fLastEnteredConfigArea");
fLastEnteredConfigArea.setAccessible(true);
}
return (String)fLastEnteredConfigArea.get(configurationBlock);
}
catch (Throwable t)
{
t.printStackTrace();
}
return null;
}
}

View File

@ -0,0 +1,97 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.pde.launch.ui.tabs;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.jetty.osgi.pde.launch.JettyLauncherMessages;
import org.eclipse.jetty.osgi.pde.launch.ui.IConfigurationAreaSettingHolder;
import org.eclipse.jetty.osgi.pde.launch.ui.JettyOSGiLaunchConfigurationInitializer;
import org.eclipse.pde.ui.launcher.AbstractLauncherTab;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
/**
* Choose a jetty.home.
* Edit the jetty.xml file.
* <p>
* Similar to org.eclipse.jdt.debug.ui.launchConfigurations.JavaArgumentsTab
* </p>
*/
public class JettyConfigurationLaunchTab extends AbstractLauncherTab
{
protected JettyHomeBlock _jettyHomeBlock;
public JettyConfigurationLaunchTab(IConfigurationAreaSettingHolder configAreaHolder)
{
_jettyHomeBlock = new JettyHomeBlock(configAreaHolder);
}
/**
* Currently does not do any validation.
*/
public void validateTab()
{
}
/**
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#createControl(Composite)
*/
public void createControl(Composite parent)
{
Composite comp = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout(1, true);
comp.setLayout(layout);
comp.setFont(parent.getFont());
GridData gd = new GridData(GridData.FILL_BOTH);
comp.setLayoutData(gd);
setControl(comp);
_jettyHomeBlock.doCreateControl(comp);
}
public String getName()
{
return JettyLauncherMessages.JettyConfigurationLaunchTab_JettyConfigurationTitle;
}
public void initializeFrom(ILaunchConfiguration configuration)
{
_jettyHomeBlock.initializeFrom(configuration);
}
/**
*
*/
public void performApply(ILaunchConfigurationWorkingCopy configuration)
{
_jettyHomeBlock.performApply(configuration);
}
/**
* This is where we initialize the selected bundles by default.
*/
public void setDefaults(ILaunchConfigurationWorkingCopy configuration)
{
_jettyHomeBlock.setDefaults(configuration);
JettyOSGiLaunchConfigurationInitializer confInitializer =
new JettyOSGiLaunchConfigurationInitializer();
confInitializer.initialize(configuration);
}
}

View File

@ -0,0 +1,189 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.pde.launch.ui.tabs;
import java.io.File;
import java.lang.reflect.Field;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.ui.WorkingDirectoryBlock;
import org.eclipse.jetty.osgi.pde.launch.JettyConfigurationConstants;
import org.eclipse.jetty.osgi.pde.launch.internal.JettyHomeHelper;
import org.eclipse.jetty.osgi.pde.launch.ui.IConfigurationAreaSettingHolder;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
/**
* Choose the jettyhome folder. A bit of a stretch to reuse the WorkingDirectoryBlock
* but it does save us a lot of UI development.
*/
public class JettyHomeBlock extends WorkingDirectoryBlock
{
private Button _editJettyXml;
private String _editedJettyXml;
private IConfigurationAreaSettingHolder _configAreaHolder;
private boolean _initializing = true;
/**
* Constructs a new working directory block.
*/
public JettyHomeBlock(IConfigurationAreaSettingHolder configAreaHolder)
{
super(JettyConfigurationConstants.ATTR_JETTY_HOME);
_configAreaHolder = configAreaHolder;
setDirty(false);
}
/**
* @return null We don't use this in the context of a java project.
*/
protected IProject getProject(ILaunchConfiguration configuration)
throws CoreException
{
return null;
}
/**
* For now just dumpt the stack trace on the console
*/
protected void log(CoreException e)
{
e.printStackTrace();
}
/**
* Calls create control of the super (which is final)
* then go an tweak the created control so that its purpose is for jetty home
* instead of a working directory selection.
*/
protected void doCreateControl(Composite parent)
{
super.createControl(parent);
Group grp = (Group)super.getControl();
grp.setText("Jetty &Home:");
//ok now a bit painful: get the composite inside which the buttons are
//add a column to the grid layout and place a button.
Button fSysButton = getfFileSystemButton();
Composite compButtons = fSysButton.getParent();
GridLayout gLayout = (GridLayout) compButtons.getLayout();
gLayout.numColumns = gLayout.numColumns+1;
_editJettyXml = createPushButton(compButtons, "Edit jetty.xml", null);
_editJettyXml.addSelectionListener(new SelectionListener()
{
public void widgetSelected(SelectionEvent e)
{
//open a text editor for jetty.xml inside a popup window.
//we are using a cheap popup.
JettyXmlEditDialog diag = new JettyXmlEditDialog(_editJettyXml.getShell(),
getCurrentJettyXml());
if (diag.open() == Window.OK) {
_editedJettyXml = diag.getNewJettyXml();
setDirty(true);
}
}
public void widgetDefaultSelected(SelectionEvent e)
{
}
});
}
/**
* Sets the default value for this field: not related to the working directory.
*/
@Override
protected void setDefaultWorkingDir()
{
//the problem is that at this point, the settings tab is not configured yet...
//so we delay the configuration of this one:
getShell().getDisplay().asyncExec(new Runnable()
{
public void run()
{
setDefaultWorkingDirectoryText(
_configAreaHolder.getConfigurationAreaLocation()
+ File.separator + "jettyhome"); //$NON-NLS-1$
_initializing = false;
}
});
}
/**
* The current content of jettyXml
*/
protected String getCurrentJettyXml()
{
return JettyHomeHelper.getCurrentJettyXml(getWorkingDirectoryText(), false);
}
@Override
public void performApply(ILaunchConfigurationWorkingCopy configuration)
{
super.performApply(configuration);
String jettyHome = getWorkingDirectoryText();
if (_initializing || jettyHome == null || jettyHome.length() == 0) {
//we are only interested in the case where the user really did press on
//Apply or "Run". furthermore before the conf area is set
//we will not be able to locate the default jettyhome.
_initializing = false;
return;
}
try
{
JettyHomeHelper.setupJettyHomeAndJettyXML(
_editedJettyXml, getWorkingDirectoryText(), false);
}
catch (Throwable t)
{
t.printStackTrace();
}
}
//introspection trick to be able to insert a button.
private static Field fFileSystemButton_field;
private Button getfFileSystemButton()
{
try
{
if (fFileSystemButton_field == null)
{
fFileSystemButton_field = WorkingDirectoryBlock.class.getDeclaredField("fFileSystemButton");
fFileSystemButton_field.setAccessible(true);
}
return (Button)fFileSystemButton_field.get(this);
}
catch (Throwable t)
{
t.printStackTrace();
}
return null;
}
}

View File

@ -0,0 +1,175 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.pde.launch.ui.tabs;
import java.io.File;
import org.eclipse.jetty.osgi.pde.launch.JettyLauncherMessages;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
/**
* A dialog that displays the content of jetty.xml
* <p>
* If someone knows how to open a standard editor provided by the IDE
* inside a popup from a modal dialog please let us know:
* that would be so much better than the simple SWT Text widget!
* </p>
*/
public class JettyXmlEditDialog extends Dialog
{
/** The text area to edit the contents of jetty.xml file */
protected Text _textField;
private Button _okButton;
/** Status label. */
private Label _statusLabel;
private boolean _isDirty = false;;
private String _lastValidatedString;
private String _jettyHome;
/**
*
* @param scope The scope in which the variable is created/edited
* @param parentShell The parent shell
* @param initValue The initial name of the variable
* before the edit. Or null if it is a bran new variable.
*/
public JettyXmlEditDialog(Shell parentShell, String currentJettyXml)
{
super(parentShell);
setShellStyle(SWT.SHELL_TRIM
| getDefaultOrientation() | SWT.RESIZE);
setBlockOnOpen(true);
_lastValidatedString = currentJettyXml;
}
/**
* @return the "OK" button
*/
public Button getGoForItButton() {
return _okButton;
}
/**
* @return The new jetty.xml contents or null if there was no modification.
*/
protected String getNewJettyXml() {
return _isDirty ? _lastValidatedString : null;
}
/**
* Invoked to update UI based on user input.
*
*/
protected void validateInput() {
String text = _textField.getText();
if (text.equals(_lastValidatedString)) {
return;
}
_isDirty = true;
_lastValidatedString = text;
Button ok = getGoForItButton();
ok.setEnabled(true);
}
/**
* {@inheritDoc}
*/
protected void configureShell(Shell newShell, String jettyHome) {
super.configureShell(newShell);
_jettyHome = jettyHome;
newShell.setText(JettyLauncherMessages.JettyXmlEditDialog_Edit_jetty_xml_title);
newShell.setSize(600, 400);
}
/**
* {@inheritDoc}
*/
protected Control createDialogArea(Composite parent) {
Composite composite = (Composite)super.createDialogArea(parent);
GridLayout gridLayout = new GridLayout();
gridLayout.numColumns = 1;
composite.setLayout(gridLayout);
Label label = new Label(composite, SWT.NONE);
String msg = JettyLauncherMessages.bind(
JettyLauncherMessages.JettyXmlEditDialog_Edit_jetty_xml,
_jettyHome + File.separatorChar + "etc" + File.separatorChar + "jetty.xml");
label.setText(msg);
_textField = new Text(composite, SWT.MULTI | SWT.BORDER /*| SWT.WRAP*/ | SWT.H_SCROLL | SWT.V_SCROLL);
_textField.addKeyListener(new KeyListener() {
public void keyReleased(KeyEvent e) {
validateInput();
}
public void keyPressed(KeyEvent e) {
}
});
if (_lastValidatedString != null) {
_textField.setText(_lastValidatedString);
}
GridData gridData = new GridData();
gridData.horizontalAlignment = GridData.FILL;
gridData.verticalAlignment = GridData.FILL;
gridData.grabExcessHorizontalSpace = true;
gridData.grabExcessVerticalSpace = true;
_textField.setLayoutData(gridData);
// _textField.setSize(500, 500);
// status label
_statusLabel = new Label(composite, SWT.NONE);
_statusLabel.setText(" "); //$NON-NLS-1$
gridData = new GridData();
gridData.horizontalAlignment = GridData.FILL;
gridData.grabExcessHorizontalSpace = true;
_statusLabel.setLayoutData(gridData);
return composite;
}
/**
* {@inheritDoc}
*/
protected void createButtonsForButtonBar(Composite parent) {
createButton(parent, IDialogConstants.CANCEL_ID, JettyLauncherMessages.JettyXmlEditDialog_Cancel, false);
_okButton = createButton(parent, IDialogConstants.OK_ID,
JettyLauncherMessages.JettyXmlEditDialog_OK, true);
_okButton.setEnabled(false);
//call validate input before the user has to type something.
//it will decide on the state of the create button.
validateInput();
}
// @Override
// public boolean close() {
// _text = getText();
// return super.close();
// }
}

View File

@ -0,0 +1,14 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Projecttemplate
Bundle-SymbolicName: org.eclipse.jetty.osgi.pde.templates;singleton:=true
Bundle-Version: 7.0.0.qualifier
Bundle-Activator: org.eclipse.jetty.osgi.pde.templates.JettyProjectTemplateActivator
Bundle-Vendor: Intalio Inc
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
org.eclipse.pde.ui;bundle-version="3.5.0",
org.eclipse.pde.ui.templates;bundle-version="3.4.100",
org.eclipse.core.resources;bundle-version="3.5.0"
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Bundle-ActivationPolicy: lazy

View File

@ -0,0 +1,7 @@
source.. = src/main/java/
output.. = target/classes/
bin.includes = META-INF/,\
.,\
plugin.xml,\
templates_3.4/,\
icons/

Binary file not shown.

After

Width:  |  Height:  |  Size: 815 B

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<!--
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
//
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
-->
<plugin>
<extension
point="org.eclipse.pde.ui.pluginContent">
<wizard
class="org.eclipse.jetty.osgi.pde.templates.HelloRFC66WebappNewWizard"
icon="$nl$/icons/jetty.png"
id="org.eclipse.jetty.osgi.pde.templates.HelloRFC66WebappNewWizard"
java="true"
name="Hello RFC-66 Web-application"
pureOSGi="true"
rcp="false"
requiresActivator="false"
ui-content="false">
<description>
Simple web-application embedded inside an OSGi bundle.
A single servlet declared in /WEB-INF/web.xml
</description>
</wizard>
<wizard
class="org.eclipse.jetty.osgi.pde.templates.TwoWebappsOneServletHandlerNewWizard"
icon="$nl$/icons/jetty.png"
id="org.eclipse.jetty.osgi.pde.templates.TwoWebappsOneServletHandlerNewWizard"
java="true"
name="Multiple Jetty webapps embedded in an OSGi bundle"
pureOSGi="true"
rcp="false"
requiresActivator="false"
ui-content="false">
<description>
Two webapps and one servlet handler configured via 3 jetty context files.
</description>
</wizard>
</extension>
</plugin>

View File

@ -0,0 +1,109 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.pde.templates;
import java.net.URL;
import java.util.ResourceBundle;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.pde.core.plugin.IPluginReference;
import org.eclipse.pde.ui.templates.OptionTemplateSection;
/**
* Simple abstract implementation of OptionTemplateSection suitable for templates defined
* in this bundle.
*/
public abstract class AbstractJettyPDETemplateSection extends OptionTemplateSection
{
public AbstractJettyPDETemplateSection()
{
super.setPageCount(getNumberOfPagesToCreateCount());
}
/**
* @return The location of the installation of this current bundle.
*/
protected URL getInstallURL() {
return JettyProjectTemplateActivator.getDefault().getBundle().getEntry("/");
}
/**
* @return The properties files for this bundle.
*/
protected ResourceBundle getPluginResourceBundle() {
return Platform.getResourceBundle(
JettyProjectTemplateActivator.getDefault().getBundle());
}
/**
* Calls internalAddPages.
* Takes care of calling markPagesAdded as required by the super implementation.
*/
public final void addPages(Wizard wizard)
{
super.markPagesAdded();
}
/**
* Actually add the pages to the wizard here.
* @param wizard
*/
protected abstract void internalAddPages(Wizard wizard);
/**
* @return the number of pages that will be added here. By default 1.
*/
protected int getNumberOfPagesToCreateCount()
{
return 1;
}
/**
* @return null By default we don't declare extension points.
* This is for OSGi bundles not eclipse plugins.
*/
public String getUsedExtensionPoint()
{
return null;
}
/**
* @return true: inherit from parent wizard
*/
public boolean isDependentOnParentWizard()
{
return true;
}
/**
* @return 1 by default we don't not do anything fancy with the progress monitors.
*/
public int getNumberOfWorkUnits()
{
return super.getNumberOfWorkUnits() + 1;
}
/**
* @return false by default we don't generate multiple projects at once right now.
*/
public IPluginReference[] getDependencies(String schemaVersion)
{
return new IPluginReference[0];
}
}

View File

@ -0,0 +1,44 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.pde.templates;
import org.eclipse.pde.ui.IFieldData;
import org.eclipse.pde.ui.templates.NewPluginTemplateWizard;
/**
* Base template wizard: set the Import-Packages header in the generated MANIFEST.MF
* to import the javax.servlet and javax.servlet.http
*/
public abstract class AbstractOSGiWebappNewWizard extends NewPluginTemplateWizard
{
/* (non-Javadoc)
* @see org.eclipse.pde.ui.templates.AbstractNewPluginTemplateWizard#init(org.eclipse.pde.ui.IFieldData)
*/
public void init(IFieldData data)
{
super.init(data);
setWindowTitle("Webapp(s) embedded in an OSGi bundle");
}
/**
* In these default examples, the only dependency are the servlet's packages.
*/
public String[] getImportPackages()
{
return new String[] {"javax.servlet;version=\"2.5.0\"", //$NON-NLS-1$
"javax.servlet.http;version=\"2.5.0\""}; //$NON-NLS-1$
}
}

View File

@ -0,0 +1,41 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.pde.templates;
import org.eclipse.pde.ui.IFieldData;
import org.eclipse.pde.ui.templates.ITemplateSection;
import org.eclipse.pde.ui.templates.NewPluginTemplateWizard;
/**
*
*/
public class HelloRFC66WebappNewWizard extends AbstractOSGiWebappNewWizard
{
/* (non-Javadoc)
* @see org.eclipse.pde.ui.templates.AbstractNewPluginTemplateWizard#init(org.eclipse.pde.ui.IFieldData)
*/
public void init(IFieldData data) {
super.init(data);
setWindowTitle("Basic webapp embedded in an OSGi bundle");
}
/* (non-Javadoc)
* @see org.eclipse.pde.ui.templates.NewPluginTemplateWizard#createTemplateSections()
*/
public ITemplateSection[] createTemplateSections() {
return new ITemplateSection[] {new HelloRFC66WebappTemplate()};
}
}

View File

@ -0,0 +1,70 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.pde.templates;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardPage;
/**
* Template to generate a simple hello wold webapp embedded in an OSGi bundle.
*/
public class HelloRFC66WebappTemplate extends AbstractJettyPDETemplateSection
{
public static final String GREETINGS = "greetings";
public static final String CONTEXT_PATH = "contextPath"; //$NON-NLS-1$
public HelloRFC66WebappTemplate()
{
addOption(GREETINGS,"Greetings message", "Howdy!",0);
addOption(CONTEXT_PATH,"Web-ContextPath","/hello",0); //$NON-NLS-1$
}
protected void internalAddPages(Wizard wizard)
{
WizardPage page = createPage(0, null);//no help for now
page.setTitle("Hello World RFC66 Webapp");
page.setDescription("Creates a webapp embedded in an OSGi bundle");
wizard.addPage(page);
}
/**
* @return 'helloRFC66Webapp' used to locate the base folder that
* contains the template files.
*/
public String getSectionId()
{
return "helloRFC66Webapp"; //$NON-NLS-1$
}
/**
* Add the Web-ContextPath to the MANIFEST.MF as required by RFC66
*/
protected void updateModel(IProgressMonitor monitor)
{
setManifestHeader("Web-ContextPath", String.valueOf(getOptions(0)[1].getValue())); //$NON-NLS-1$ //$NON-NLS-2$]
}
/* (non-Javadoc)
* @see org.eclipse.pde.ui.templates.ITemplateSection#getFoldersToInclude()
*/
public String[] getNewFiles() {
return new String[] {"WEB-INF/web.xml"};
}
}

View File

@ -0,0 +1,70 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.pde.templates;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
/**
* The activator class controls the plug-in life cycle
*/
public class JettyProjectTemplateActivator extends AbstractUIPlugin {
// The plug-in ID
public static final String PLUGIN_ID = "org.eclipse.jetty.osgi.pde.projecttemplate";
// The shared instance
private static JettyProjectTemplateActivator plugin;
/**
* The constructor
*/
public JettyProjectTemplateActivator()
{
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext context) throws Exception
{
super.start(context);
plugin = this;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception
{
plugin = null;
super.stop(context);
}
/**
* Returns the shared instance
*
* @return the shared instance
*/
public static JettyProjectTemplateActivator getDefault()
{
return plugin;
}
}

View File

@ -0,0 +1,40 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.pde.templates;
import org.eclipse.pde.ui.IFieldData;
import org.eclipse.pde.ui.templates.ITemplateSection;
/**
*
*/
public class TwoWebappsOneServletHandlerNewWizard extends AbstractOSGiWebappNewWizard
{
/* (non-Javadoc)
* @see org.eclipse.pde.ui.templates.AbstractNewPluginTemplateWizard#init(org.eclipse.pde.ui.IFieldData)
*/
public void init(IFieldData data) {
super.init(data);
setWindowTitle("Two Webapps and one servlet embedded in an OSGi bundle");
}
/* (non-Javadoc)
* @see org.eclipse.pde.ui.templates.NewPluginTemplateWizard#createTemplateSections()
*/
public ITemplateSection[] createTemplateSections() {
return new ITemplateSection[] {new TwoWebappsOneServletHandlerTemplate()};
}
}

View File

@ -0,0 +1,78 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.pde.templates;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardPage;
/**
* Template that generates jetty webapps.
*/
public class TwoWebappsOneServletHandlerTemplate extends AbstractJettyPDETemplateSection
{
public static final String GREETINGS = "greetings"; //$NON-NLS-1$
public static final String CONTEXT_PATH_APP_1 = "contextPathApp1"; //$NON-NLS-1$
public static final String CONTEXT_PATH_APP_2 = "contextPathApp2"; //$NON-NLS-1$
public TwoWebappsOneServletHandlerTemplate()
{
addOption(GREETINGS,"Greetings message", "Howdy!",0);
addOption(CONTEXT_PATH_APP_1,"Webapp 1 Context Path","/app1",0); //$NON-NLS-1$
addOption(CONTEXT_PATH_APP_2,"Webapp 2 Context Path","/app2",0); //$NON-NLS-1$
}
public void internalAddPages(Wizard wizard)
{
WizardPage page = createPage(0, null);
page.setTitle("Two webapps and one servlet in an OSGi bundle");
page.setDescription("Creates multiple jetty webapps embedded in an OSGi bundle");
wizard.addPage(page);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.pde.ui.templates.OptionTemplateSection#getSectionId()
*/
public String getSectionId()
{
return "twoWebappsOneServletHandler"; //$NON-NLS-1$
}
/**
* Add the Jetty-ContextFilePath to the MANIFEST.MF as required for
* jetty-osgi to be able to identify the embedded webapps.
*/
protected void updateModel(IProgressMonitor monitor)
{
setManifestHeader("Jetty-ContextFilePath",
"jettycontexts/myservlet.xml, " + //$NON-NLS-1$ //$NON-NLS-2$
"jettycontexts/app1.xml, jettycontexts/app2.xml"); //$NON-NLS-1$ //$NON-NLS-2$
}
/* (non-Javadoc)
* @see org.eclipse.pde.ui.templates.ITemplateSection#getFoldersToInclude()
*/
public String[] getNewFiles() {
return new String[] {"war1/WEB-INF/web.xml",
"war2/WEB-INF/web.xml", //$NON-NLS-1$ //$NON-NLS-2$
"jettycontexts/app1.xml", "jettycontexts/app2.xml", //$NON-NLS-1$ //$NON-NLS-2$
"jettycontexts/myservlet.xml"}; //$NON-NLS-1$
}
}

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>Hello Webapp</display-name>
<servlet>
<servlet-name>theservlet</servlet-name>
<servlet-class>$packageName$.Servlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>theservlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>

View File

@ -0,0 +1,24 @@
package $packageName$;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
public class $activator$ implements BundleActivator {
/*
* (non-Javadoc)
* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext context) throws Exception {
System.out.println("$startMessage$");
}
/*
* (non-Javadoc)
* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception {
System.out.println("$stopMessage$");
}
}

View File

@ -0,0 +1,26 @@
package $packageName$;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Servlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.getWriter().write("$greetings$");
}
}

View File

@ -0,0 +1,24 @@
package $packageName$;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
public class $activator$ implements BundleActivator {
/*
* (non-Javadoc)
* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext context) throws Exception {
System.out.println("$startMessage$");
}
/*
* (non-Javadoc)
* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception {
System.out.println("$stopMessage$");
}
}

View File

@ -0,0 +1,29 @@
package $packageName$;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Servlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.getWriter().write(req.getContextPath() + ": $greetings$");
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">$contextPathApp1$</Set>
<Set name="war"><Property name="this.bundle.install"/>/war2</Set>
</Configure>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">$contextPathApp2$</Set>
<Set name="war"><Property name="this.bundle.install"/>/war2</Set>
</Configure>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure class="org.eclipse.jetty.servlet.ServletContextHandler">
<Call name="addServlet">
<Arg>$packageName$.Servlet</Arg>
<Arg>/theservlet</Arg>
</Call>
</Configure>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>Hello Webapp</display-name>
<servlet>
<servlet-name>theservlet</servlet-name>
<servlet-class>$packageName$.Servlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>theservlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>Hello Webapp</display-name>
<servlet>
<servlet-name>theservlet</servlet-name>
<servlet-class>$packageName$.Servlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>theservlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>

View File

@ -30,6 +30,7 @@ jetty-7.0.1-SNAPSHOT
+ Promoted Jetty WebApp Verifier from Sandbox
+ Refactored continuation test harnessess
+ Fixed client abort asocciation
+ CQ-3581 jetty OSGi contribution
jetty-7.0.0.v20091005 5 October 2009
291340 Race condition in onException() notifications