Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'wip-osgi'

  • Loading branch information...
commit e8be83383e88728b27dfbc9ec232f5b7c2fbc43e 2 parents 494f7a2 + 8b6ec19
Heiko Seeberger authored
View
78 lift-osgi/pom.xml
@@ -0,0 +1,78 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>net.liftweb</groupId>
+ <artifactId>lift</artifactId>
+ <version>1.1-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>lift-osgi</artifactId>
+ <name>Lift OSGi</name>
+ <description>OSGi support for the Lift web framework.</description>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.scala-lang</groupId>
+ <artifactId>scala-library</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.scalamodules</groupId>
+ <artifactId>scalamodules-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.web</groupId>
+ <artifactId>pax-web-bundle</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.swissbox</groupId>
+ <artifactId>pax-swissbox-extender</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>net.liftweb</groupId>
+ <artifactId>lift-webkit</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>net.liftweb</groupId>
+ <artifactId>lift-util</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Private-Package>net.liftweb.osgi.internal.*</Private-Package>
+ <Bundle-Activator>net.liftweb.osgi.internal.Activator</Bundle-Activator>
+ <Import-Package>javax.servlet.*;version="[2.5,2.6)",*</Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <repositories>
+ <repository>
+ <id>opsj4-releases</id>
+ <url>http://repository.ops4j.org/maven2</url>
+ </repository>
+ </repositories>
+
+</project>
View
158 lift-osgi/src/main/scala/net/liftweb/osgi/internal/Activator.scala
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2007-2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+package net.liftweb.osgi.internal
+
+import java.util.{List => JList}
+import java.util.concurrent.atomic.AtomicReference
+import javax.servlet.http.{HttpServletRequest, HttpServletResponse}
+import net.liftweb.http.LiftFilter
+import net.liftweb.util.{Box, Slf4jLogBoot}
+import org.ops4j.pax.swissbox.extender._
+import org.ops4j.pax.web.service.WebContainer
+import org.osgi.framework.{Bundle, BundleActivator, BundleContext}
+import org.osgi.service.http.HttpContext
+import org.scalamodules.core.{Adding, Modified, Removed}
+import org.scalamodules.core.RichBundleContext.toRichBundleContext
+
+/**
+ * <p>This activator enables OSGi support for Lift.</p>
+ * <p>First logging is switched to SLF4J, because Log4j does not work in
+ * OSGi space. Second a Lift extender is created watching Lift-powered
+ * bundles (<i>Lift-Config</i> manifest header). Third a Lift HttpContext is
+ * created delegating requests for resources to the Lift-powered bundles.
+ * Finally a modified LiftFilter (no booting) is registered.</p>
+ */
+class Activator extends BundleActivator {
+
+ override def start(context: BundleContext) {
+
+ // Log4j is a bad OSGi citizen!
+ Slf4jLogBoot.enable()
+
+ // Create and start Lift extender
+ bundleWatcher = new BundleWatcher[ManifestEntry](
+ context,
+ new BundleManifestScanner(new RegexKeyManifestFilter("Lift-Config")),
+ LiftBundleObserver)
+ bundleWatcher.start()
+
+ // Register resources and LiftFilter
+ context track classOf[WebContainer] on {
+ case Adding(webContainer, _) => {
+ if ((webContainerHolder getAndSet webContainer) == null) {
+ val liftHttpContext = LiftHttpContext(webContainer.createDefaultHttpContext)
+ webContainer.registerResources("/", "/", liftHttpContext)
+ webContainer.registerFilter(OsgiLiftFilter, Array("/*"), null, null, liftHttpContext)
+ }
+ }
+ case Removed(webContainer, _) => webContainerHolder.compareAndSet(webContainer, null)
+ }
+ }
+
+ override def stop(context: BundleContext) {
+
+ // Unregister resources and LiftFilter
+ webContainerHolder.get match {
+ case null => // Nothing!
+ case webContainer => {
+ webContainer unregisterFilter OsgiLiftFilter
+ webContainer unregister "/"
+ }
+ }
+
+ // Stop Lift extender
+ bundleWatcher.stop()
+ }
+
+ private val webContainerHolder = new AtomicReference[WebContainer]
+
+ private var bundleWatcher: BundleWatcher[ManifestEntry] = _
+}
+
+/**
+ * Observer for a Lift-powered bundle.
+ */
+private object LiftBundleObserver extends BundleObserver[ManifestEntry] {
+
+ type LiftBundles = Map[Bundle, LiftBundleConfig]
+
+ val liftBundles = new AtomicReference[LiftBundles](Map.empty)
+
+ override def addingEntries(bundle: Bundle, entries: JList[ManifestEntry]) {
+ assert(1 == entries.size, "Expecting exactly one manifest entry!")
+ val config = LiftBundleConfig(entries get 0)
+ update(lb => lb + (bundle -> config))
+ }
+
+ override def removingEntries(bundle: Bundle, entries: JList[ManifestEntry]) {
+ assert(1 == entries.size, "Expecting exactly one manifest entry!")
+ update(lb => lb - bundle)
+ }
+
+ private def update[T](change: LiftBundles => LiftBundles) {
+ val old = liftBundles.get
+ if (!liftBundles.compareAndSet(old, change(old))) {
+ update(change)
+ }
+ }
+}
+
+/**
+ * Special LiftFilter for OSGi space: No booting!
+ */
+private object OsgiLiftFilter extends LiftFilter {
+ override def bootLift(loader : Box[String]) { /* Nothing! */ }
+}
+
+/**
+ * Configuration of a Lift-powered bundle.
+ */
+private case class LiftBundleConfig(manifestEntry: ManifestEntry) {
+
+ assert(manifestEntry != null, "ManifestEntry must not be null!")
+
+ // TODO: Parse manifest entry and initialize webapp
+ def mapResource(s: String) = ("/webapp/" + s).replaceAll("//", "/")
+}
+
+/**
+ * Special HttpContext that delegates resource lookups to observerd
+ * Lift-powered bundles and other methods to wrapped HttpContext.
+ */
+private case class LiftHttpContext(context: HttpContext) extends HttpContext {
+
+ assert(context != null, "HttpContext must not be null!")
+
+ override def getMimeType(s: String) = context getMimeType s
+
+ override def getResource(s: String) = {
+ val liftBundles = LiftBundleObserver.liftBundles.get.toSeq.projection
+ // TODO: The following probably could be done better!
+ liftBundles flatMap {
+ liftBundle => liftBundle._1 getResource (liftBundle._2 mapResource s) match {
+ case null => None
+ case res => Some(res)
+ }
+ } firstOption match {
+ case None => null
+ case Some(res) => res
+ }
+ }
+
+ override def handleSecurity(req: HttpServletRequest, res: HttpServletResponse) =
+ context.handleSecurity(req, res)
+}
View
11 lift-util/pom.xml
@@ -117,6 +117,17 @@
<build>
<plugins>
<plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Export-Package>net.liftweb.util.*;version="${pom.version}"</Export-Package>
+ <Import-Package>org.slf4j.*;resolution:="optional",*</Import-Package>
+ <DynamicImport-Package>*</DynamicImport-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
<groupId>net.sf.alchim</groupId>
<artifactId>yuicompressor-maven-plugin</artifactId>
<executions>
View
13 lift/pom.xml
@@ -121,7 +121,7 @@
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
- <version>[6.1.6,)</version>
+ <version>[6.1.6,7)</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -146,6 +146,17 @@
<build>
<plugins>
<plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Export-Package>!net.liftweb.util.*,net.liftweb.*;version="${pom.version}"</Export-Package>
+ <Import-Package>org.slf4j.*;resolution:="optional",*</Import-Package>
+ <DynamicImport-Package>*</DynamicImport-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
<groupId>net.sf.alchim</groupId>
<artifactId>yuicompressor-maven-plugin</artifactId>
<executions>
View
81 pom.xml
@@ -130,6 +130,15 @@ Lift is a scala web framework.
<email>java [at] chen-becker.org</email>
<timezone>-7</timezone>
</developer>
+ <developer>
+ <id>heiko.seeberger</id>
+ <name>Heiko Seeberger</name>
+ <email>heiko [dot] seeberger [at] googlemail [dot] com</email>
+ <timezone>+1</timezone>
+ <roles>
+ <role>OSGi expert and Scala enthusiast</role>
+ </roles>
+ </developer>
</developers>
<mailingLists>
@@ -158,6 +167,7 @@ Lift is a scala web framework.
<modules>
<module>lift-util</module>
<module>lift</module>
+ <module>lift-osgi</module>
<module>lift-mapper</module>
<module>lift-machine</module>
<module>lift-record</module>
@@ -213,6 +223,36 @@ Lift is a scala web framework.
<scope>provided</scope>
</dependency>
<dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>1.2.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>1.2.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.scalamodules</groupId>
+ <artifactId>scalamodules-core</artifactId>
+ <version>1.1-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.web</groupId>
+ <artifactId>pax-web-bundle</artifactId>
+ <version>0.6.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.swissbox</groupId>
+ <artifactId>pax-swissbox-extender</artifactId>
+ <version>0.2.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
<groupId>com.ibm.icu</groupId>
<artifactId>icu4j</artifactId>
<version>3.4.4</version>
@@ -230,6 +270,16 @@ Lift is a scala web framework.
</extension>
</extensions>
<plugins>
+ <!-- Helps with importing Maven projects into Eclipse correctly -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.0.2</version>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
<plugin>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
@@ -254,7 +304,7 @@ Lift is a scala web framework.
<scalaVersion>${scala.version}</scalaVersion>
</configuration>
</plugin>
- <plugin>
+ <!--plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<configuration>
@@ -270,7 +320,7 @@ Lift is a scala web framework.
<classpathContainer>ch.epfl.lamp.sdt.launching.SCALA_CONTAINER</classpathContainer>
</classpathContainers>
</configuration>
- </plugin>
+ </plugin-->
<plugin>
<inherited>true</inherited>
<artifactId>maven-source-plugin</artifactId>
@@ -288,7 +338,6 @@ Lift is a scala web framework.
<artifactId>maven-changes-plugin</artifactId>
<version>2.0</version>
</plugin>
-
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
@@ -301,8 +350,32 @@ Lift is a scala web framework.
</archive>
</configuration>
</plugin>
-
</plugins>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.0.0</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-RequiredExecutionEnvironment>J2SE-1.5</Bundle-RequiredExecutionEnvironment>
+ <_versionpolicy>[$(@),$(version;=+;$(@)))</_versionpolicy>
+ </instructions>
+ </configuration>
+ <executions>
+ <execution>
+ <id>create-bundle</id>
+ <phase>package</phase>
+ <goals>
+ <goal>bundle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </pluginManagement>
</build>
<reporting>
<plugins>
View
20 sites/examples-osgi/hello/hello.composite
@@ -0,0 +1,20 @@
+scan-bundle:mvn:javax.mail/mail/1.4
+scan-bundle:mvn:javax.activation/activation/1.1
+scan-bundle:mvn:commons-httpclient/commons-httpclient/3.1
+scan-bundle:mvn:commons-fileupload/commons-fileupload/1.2.1
+scan-bundle:mvn:commons-collections/commons-collections/3.2.1
+scan-bundle:mvn:commons-codec/commons-codec/1.3
+# required by commons-fileupload
+scan-bundle:mvn:commons-io/commons-io/1.3.2
+
+scan-bundle:mvn:org.scalamodules/scalamodules-core/1.1-SNAPSHOT
+scan-bundle:mvn:org.scalamodules/scalamodules-util/1.1-SNAPSHOT
+
+scan-bundle:mvn:net.liftweb/lift-util/1.1-SNAPSHOT@update
+scan-bundle:mvn:net.liftweb/lift-webkit/1.1-SNAPSHOT@update
+scan-bundle:mvn:net.liftweb/lift-osgi/1.1-SNAPSHOT@update
+scan-bundle:mvn:org.ops4j.pax.swissbox/pax-swissbox-extender/0.2.0
+scan-bundle:mvn:org.ops4j.pax.swissbox/pax-swissbox-lifecycle/0.2.0
+scan-bundle:mvn:org.ops4j.base/ops4j-base-lang/0.5.0
+
+scan-bundle:mvn:net.liftweb/examples-osgi-hello/1.1-SNAPSHOT@update
View
32 sites/examples-osgi/hello/pom.xml
@@ -0,0 +1,32 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>net.liftweb</groupId>
+ <artifactId>lift</artifactId>
+ <version>1.1-SNAPSHOT</version>
+ </parent>
+
+ <groupId>net.liftweb</groupId>
+ <artifactId>examples-osgi-hello</artifactId>
+ <name>OSGi Examples for Lift - Hello</name>
+ <packaging>jar</packaging>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Include-Resource>webapp=src/main/webapp</Include-Resource>
+ <Lift-Config>xxx</Lift-Config>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
View
3  sites/examples-osgi/hello/src/main/webapp/index.html
@@ -0,0 +1,3 @@
+<lift:surround with="default" at="content">
+ <h2>Welcome to Lift on OSGi!</h2>
+</lift:surround>
View
28 sites/examples-osgi/pom.xml
@@ -0,0 +1,28 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>net.liftweb</groupId>
+ <artifactId>lift</artifactId>
+ <version>1.1-SNAPSHOT</version>
+ </parent>
+
+ <groupId>net.liftweb.examples</groupId>
+ <artifactId>osgi</artifactId>
+ <name>OSGi Examples for Lift</name>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>hello</module>
+ </modules>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.scala-lang</groupId>
+ <artifactId>scala-library</artifactId>
+ </dependency>
+ </dependencies>
+
+</project>
View
1  sites/pom.xml
@@ -12,6 +12,7 @@
<packaging>pom</packaging>
<modules>
<module>example</module>
+ <module>examples-osgi</module>
<module>skittr</module>
<module>hellolift</module>
<module>hellodarwin</module>
Please sign in to comment.
Something went wrong with that request. Please try again.