Explorar o código

add onejar module

Jason Rivard %!s(int64=7) %!d(string=hai) anos
pai
achega
deca9b1e3a

+ 46 - 0
onejar/onejar-assembly.xml

@@ -0,0 +1,46 @@
+<!--
+  ~ Password Management Servlets (PWM)
+  ~ http://www.pwm-project.org
+  ~
+  ~ Copyright (c) 2006-2009 Novell, Inc.
+  ~ Copyright (c) 2009-2017 The PWM Project
+  ~
+  ~ This program is free software; you can redistribute it and/or modify
+  ~ it under the terms of the GNU General Public License as published by
+  ~ the Free Software Foundation; either version 2 of the License, or
+  ~ (at your option) any later version.
+  ~
+  ~ This program is distributed in the hope that it will be useful,
+  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+  ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  ~ GNU General Public License for more details.
+  ~
+  ~ You should have received a copy of the GNU General Public License
+  ~ along with this program; if not, write to the Free Software
+  ~ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  -->
+
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
+
+    <id>onejar</id>
+    <formats>
+        <format>jar</format>
+    </formats>
+    <includeBaseDirectory>false</includeBaseDirectory>
+    <dependencySets>
+        <dependencySet>
+            <outputDirectory>/</outputDirectory>
+            <useProjectArtifact>true</useProjectArtifact>
+            <unpack>true</unpack>
+            <scope>runtime</scope>
+        </dependencySet>
+    </dependencySets>
+    <files>
+        <file>
+            <source>${project.basedir}${file.separator}..${file.separator}server${file.separator}target${file.separator}pwm-${project.version}.war</source>
+            <outputDirectory>/</outputDirectory>
+            <destName>embed.war</destName>
+        </file>
+    </files>
+</assembly>

+ 150 - 0
onejar/pom.xml

@@ -0,0 +1,150 @@
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <parent>
+        <groupId>org.pwm-project</groupId>
+        <artifactId>pwm-parent</artifactId>
+        <version>1.8.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>pwm-onejar</artifactId>
+
+    <packaging>jar</packaging>
+
+    <name>PWM Password Self Service: Executable Jar</name>
+
+    <properties>
+        <tomcat.version>9.0.4</tomcat.version>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-enforcer-plugin</artifactId>
+                <version>3.0.0-M1</version>
+                <executions>
+                    <execution>
+                        <id>enforce-maven</id>
+                        <goals>
+                            <goal>enforce</goal>
+                        </goals>
+                        <configuration>
+                            <rules>
+                                <requireMavenVersion>
+                                    <version>${pwm.minimum.maven.version}</version>
+                                </requireMavenVersion>
+                            </rules>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <!-- prevent normal jar from being built -->
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>3.0.2</version>
+                <executions>
+                    <execution>
+                        <id>default-jar</id>
+                        <phase>never</phase>
+                        <configuration>
+                            <finalName>unwanted</finalName>
+                            <classifier>unwanted</classifier>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.7.0</version>
+                <configuration>
+                    <source>${maven.compiler.source}</source>
+                    <target>${maven.compiler.target}</target>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <version>3.1.0</version>
+
+                <configuration>
+                    <appendAssemblyId>false</appendAssemblyId>
+                    <descriptors>
+                        <descriptor>onejar-assembly.xml</descriptor>
+                    </descriptors>
+                    <archive>
+                        <manifestEntries>
+                            <Main-Class>password.pwm.TomcatOneJarMain</Main-Class>
+                            <Implementation-Title>${project.name}</Implementation-Title>
+                            <Implementation-Version>${project.version}</Implementation-Version>
+                            <Implementation-Vendor>${project.organization.name}</Implementation-Vendor>
+                            <Implementation-URL>${project.organization.url}</Implementation-URL>
+                            <Implementation-Build>${build.number}</Implementation-Build>
+                            <Implementation-Revision>${build.revision}</Implementation-Revision>
+                            <Implementation-Version-Display>v${project.version} b${build.number} r${build.revision}</Implementation-Version-Display>
+                        </manifestEntries>
+                    </archive>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>assemble-all</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+
+        <!--
+        This is included via the assembly plugin descriptor, so its not really required here but keeps
+        the module build order correct.
+        -->
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>pwm</artifactId>
+            <version>${project.version}</version>
+            <type>war</type>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- embedded tomcat -->
+        <dependency>
+            <groupId>org.apache.tomcat</groupId>
+            <artifactId>tomcat-catalina</artifactId>
+            <version>${tomcat.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tomcat</groupId>
+            <artifactId>tomcat-util</artifactId>
+            <version>${tomcat.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tomcat.embed</groupId>
+            <artifactId>tomcat-embed-core</artifactId>
+            <version>${tomcat.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tomcat.embed</groupId>
+            <artifactId>tomcat-embed-jasper</artifactId>
+            <version>${tomcat.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-cli</groupId>
+            <artifactId>commons-cli</artifactId>
+            <version>1.4</version>
+        </dependency>
+    </dependencies>
+</project>

+ 62 - 0
onejar/src/main/java/password/pwm/TomcatConfig.java

@@ -0,0 +1,62 @@
+package password.pwm;
+
+import java.io.File;
+import java.io.InputStream;
+
+class TomcatConfig {
+    private int port;
+    private File applicationPath;
+    private File workingPath;
+    private InputStream war;
+    private String context;
+
+    public int getPort( )
+    {
+        return port;
+    }
+
+    public void setPort( final int port )
+    {
+        this.port = port;
+    }
+
+    public File getApplicationPath( )
+    {
+        return applicationPath;
+    }
+
+    public void setApplicationPath( final File applicationPath )
+    {
+        this.applicationPath = applicationPath;
+    }
+
+    public File getWorkingPath( )
+    {
+        return workingPath;
+    }
+
+    public void setWorkingPath( final File workingPath )
+    {
+        this.workingPath = workingPath;
+    }
+
+    public InputStream getWar( )
+    {
+        return war;
+    }
+
+    public void setWar( final InputStream war )
+    {
+        this.war = war;
+    }
+
+    public String getContext( )
+    {
+        return context;
+    }
+
+    public void setContext( final String context )
+    {
+        this.context = context;
+    }
+}

+ 335 - 0
onejar/src/main/java/password/pwm/TomcatOneJarMain.java

@@ -0,0 +1,335 @@
+package password.pwm;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.connector.Connector;
+import org.apache.catalina.connector.CoyoteAdapter;
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.util.ServerInfo;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+
+import javax.servlet.ServletException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.Socket;
+import java.net.URL;
+import java.nio.file.FileVisitOption;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import java.util.logging.Logger;
+
+public class TomcatOneJarMain
+{
+    private static final  Logger LOGGER = Logger.getLogger(TomcatOneJarMain.class.getName());
+
+    private static final String ARG_APP_PATH = "applicationPath";
+    private static final String ARG_WORK_PATH = "workPath";
+    private static final String ARG_VERSION = "version";
+    private static final String ARG_HELP = "help";
+    private static final String ARG_WARFILE = "war";
+    private static final String ARG_PORT = "port";
+    private static final String ARG_CONTEXT = "context";
+
+    private static final String DEFAULT_CONTEXT = "pwm";
+    private static final int DEFAULT_PORT = 8080;
+    private static final String DEFAULT_WORK_DIR_NAME = ".pwm-workpath";
+
+    private static final String EMBED_WAR_NAME = "embed.war";
+
+    public static void main(final String[] args) throws ServletException, IOException, LifecycleException
+    {
+        if (args == null || args.length == 0) {
+            outputHelp();
+        } else
+        {
+            final CommandLine commandLine = parseOptions( args );
+            if ( commandLine.hasOption( ARG_VERSION ) ) {
+                System.out.println( getVersion() );
+            } else if ( commandLine.hasOption( ARG_HELP ) ) {
+                outputHelp();
+            } else {
+                final TomcatConfig tomcatConfig = makeTomcatConfig( commandLine );
+                startTomcat(tomcatConfig);
+            }
+        }
+    }
+
+    private static TomcatConfig makeTomcatConfig(final CommandLine commandLine) throws IOException
+    {
+        final TomcatConfig tomcatConfig = new TomcatConfig();
+        tomcatConfig.setApplicationPath( parseFileOption( commandLine, ARG_APP_PATH ) );
+
+        if (commandLine.hasOption( ARG_CONTEXT )) {
+            tomcatConfig.setContext( commandLine.getOptionValue( ARG_CONTEXT ) );
+        } else {
+            tomcatConfig.setContext( DEFAULT_CONTEXT );
+        }
+
+        if (commandLine.hasOption( ARG_WARFILE )) {
+            final File inputWarFile = new File (commandLine.getOptionValue( ARG_WARFILE ));
+            if (!inputWarFile.exists()) {
+                System.out.println( "output war file " + inputWarFile.getAbsolutePath() + "does not exist" );
+                System.exit( -1 );
+                return null;
+            }
+            tomcatConfig.setWar( new FileInputStream( inputWarFile ) );
+        } else {
+            tomcatConfig.setWar( getEmbeddedWar() );
+        }
+
+        tomcatConfig.setPort( DEFAULT_PORT );
+        if (commandLine.hasOption( ARG_PORT )) {
+            try {
+                tomcatConfig.setPort( Integer.parseInt( commandLine.getOptionValue( ARG_PORT ) ) );
+            } catch (NumberFormatException e) {
+                System.out.println( ARG_PORT + " argument must be numeric" );
+                System.exit( -1 );
+            }
+        }
+
+        if ( checkIfPortInUse( tomcatConfig.getPort())) {
+            System.out.println( "port " + tomcatConfig.getPort() +  " is in use" );
+            System.exit( -1 );
+        }
+
+        if (commandLine.hasOption( ARG_WORK_PATH )) {
+            tomcatConfig.setWorkingPath( parseFileOption( commandLine, ARG_WORK_PATH ) );
+        } else {
+            tomcatConfig.setWorkingPath( figureDefaultWorkPath(tomcatConfig) );
+        }
+
+        return tomcatConfig;
+    }
+
+    private static File parseFileOption(final  CommandLine commandLine, final String argName) {
+        if (!commandLine.hasOption( argName )) {
+            outAndExit(  "option " + argName + " required");
+        }
+        final File file = new File(commandLine.getOptionValue( argName ));
+        if (!file.isAbsolute()) {
+            outAndExit( "a fully qualified file path name is required for " + argName);
+        }
+        if (!file.exists()) {
+            outAndExit( "path specified by " + argName + " must exist");
+        }
+        return file;
+    }
+
+    private static void outputHelp() throws IOException
+    {
+        final HelpFormatter formatter = new HelpFormatter();
+        System.out.println( getVersion() );
+        System.out.println( "usage:" );
+        formatter.printOptions( System.console().writer(), HelpFormatter.DEFAULT_WIDTH, makeOptions(),3 , 8);
+    }
+
+    private static void startTomcat( final TomcatConfig tomcatConfig) throws ServletException, IOException
+    {
+        purgeDirectory( tomcatConfig.getWorkingPath().toPath() );
+        {
+            final Path outputPath = tomcatConfig.getWorkingPath().toPath().resolve( EMBED_WAR_NAME );
+            final InputStream warSource = tomcatConfig.getWar();
+            Files.copy(warSource, outputPath);
+        }
+        System.setProperty( "PWM_APPLICATIONPATH", tomcatConfig.getApplicationPath().getAbsolutePath() );
+
+        final Tomcat tomcat = new Tomcat();
+
+        {
+            final File basePath = new File( tomcatConfig.getWorkingPath().getPath() + File.separator + "b" );
+            basePath.mkdir();
+            tomcat.setBaseDir( basePath.getAbsolutePath() );
+        }
+        {
+            final File basePath = new File( tomcatConfig.getWorkingPath().getPath() + File.separator + "a" );
+            basePath.mkdir();
+            tomcat.getServer().setCatalinaBase( basePath );
+            tomcat.getServer().setCatalinaHome( basePath );
+        }
+        {
+            final File workPath = new File( tomcatConfig.getWorkingPath().getPath() + File.separator + "w" );
+            workPath.mkdir();
+            tomcat.getHost().setAppBase( workPath.getAbsolutePath() );
+        }
+
+        tomcat.setConnector( makeConnector( tomcatConfig ) );
+
+        tomcat.setPort( DEFAULT_PORT );
+        tomcat.getConnector();
+
+        tomcat.getHost().setAutoDeploy(false);
+        tomcat.getHost().setDeployOnStartup(false);
+
+        final String warPath = tomcatConfig.getWorkingPath().getAbsolutePath() + File.separator + EMBED_WAR_NAME;
+        final Context pwmContext = tomcat.addWebapp( "/" + tomcatConfig.getContext(), warPath );
+        LOGGER.info("Deployed " + pwmContext.getBaseName() + " as " + pwmContext.getBaseName());
+
+        try {
+            tomcat.start();
+        } catch (LifecycleException e) {
+            outAndExit( "unable to start tomcat: " + e.getMessage() );
+        }
+        LOGGER.info("tomcat started on " + tomcat.getHost());
+
+        tomcat.getServer().await();
+    }
+
+    private static Connector makeConnector(final TomcatConfig tomcatConfig) {
+        final Connector connector = new Connector("HTTP/1.1");
+        connector.setPort(tomcatConfig.getPort());
+        return connector;
+    }
+
+    private static CommandLine parseOptions(final String[] args) {
+        final CommandLineParser parser = new DefaultParser();
+        try {
+            return parser.parse( makeOptions(), args);
+        } catch ( ParseException e ) {
+            outAndExit(  "error parsing commandline: " + e.getMessage() );
+        }
+        return null;
+    }
+
+    private static Options makeOptions() {
+        final Map<String,Option> optionMap = new TreeMap<>(  );
+
+        optionMap.put(ARG_APP_PATH,Option.builder(ARG_APP_PATH)
+                .desc( "application path (required)" )
+                .numberOfArgs( 1 )
+                .required(false)
+                .build());
+
+        optionMap.put(ARG_WORK_PATH,Option.builder(ARG_WORK_PATH)
+                .desc( "temporary work path" )
+                .numberOfArgs( 1 )
+                .required(false)
+                .build());
+
+        optionMap.put(ARG_VERSION,Option.builder(ARG_VERSION)
+                .desc( "show version" )
+                .numberOfArgs( 0 )
+                .required(false)
+                .build());
+
+        optionMap.put(ARG_PORT,Option.builder()
+                .longOpt( ARG_PORT )
+                .desc( "web server port (default " + DEFAULT_PORT + ")" )
+                .numberOfArgs( 1 )
+                .build() );
+
+        optionMap.put(ARG_CONTEXT,Option.builder()
+                .longOpt( ARG_CONTEXT )
+                .desc( "context (url path) name (default " + DEFAULT_CONTEXT + ")" )
+                .numberOfArgs( 1 )
+                .build() );
+
+        optionMap.put(ARG_HELP,Option.builder(ARG_HELP)
+                .desc( "show this help" )
+                .numberOfArgs( 0 )
+                .required(false)
+                .build());
+
+        optionMap.put(ARG_WARFILE,Option.builder(ARG_WARFILE)
+                .desc( "source war file (default embedded)" )
+                .numberOfArgs( 1 )
+                .required(false)
+                .build());
+
+        final Options options = new Options();
+        optionMap.values().forEach( options::addOption );
+        return options;
+    }
+
+    private static InputStream getEmbeddedWar() throws IOException
+    {
+        final Class clazz = TomcatOneJarMain.class;
+        final String className = clazz.getSimpleName() + ".class";
+        final String classPath = clazz.getResource(className).toString();
+        if (!classPath.startsWith("jar")) {
+            outAndExit("not running from war, war option must be specified");
+            return null;
+        }
+        final String warPath = classPath.substring(0, classPath.lastIndexOf("!") + 1) +
+                "/" + EMBED_WAR_NAME;
+        return new URL(warPath).openStream();
+    }
+
+    private static String getVersion() throws IOException
+    {
+        final Class clazz = TomcatOneJarMain.class;
+        final String className = clazz.getSimpleName() + ".class";
+        final String classPath = clazz.getResource(className).toString();
+        if (!classPath.startsWith("jar")) {
+            // Class not from JAR
+            return "--version missing--";
+        }
+        final String manifestPath = classPath.substring(0, classPath.lastIndexOf("!") + 1) +
+                "/META-INF/MANIFEST.MF";
+        final Manifest manifest = new Manifest(new URL(manifestPath).openStream());
+        final Attributes attr = manifest.getMainAttributes();
+        return attr.getValue("Implementation-Version-Display")
+                + ", " + ServerInfo.getServerInfo();
+    }
+
+    private static void purgeDirectory(final Path rootPath)
+            throws IOException
+    {
+        System.out.println("purging work directory: " + rootPath);
+        Files.walk(rootPath, FileVisitOption.FOLLOW_LINKS)
+                .sorted( Comparator.reverseOrder())
+                .map(Path::toFile)
+                .filter( file -> !rootPath.toString().equals( file.getPath() ) )
+                .forEach(File::delete);
+    }
+
+    private static boolean checkIfPortInUse( final int portNumber) {
+        boolean result;
+
+        try {
+            Socket s = new Socket("localhost", portNumber);
+            s.close();
+            result = true;
+        } catch(IOException e) {
+            result = false;
+        }
+
+        return(result);
+    }
+
+    private static File figureDefaultWorkPath(final TomcatConfig tomcatConfig) {
+        final String userHomePath = System.getProperty( "user.home" );
+        if (userHomePath != null && !userHomePath.isEmpty()) {
+            final File basePath = new File(userHomePath + File.separator
+                    + "." + DEFAULT_CONTEXT);
+            basePath.mkdir();
+            final File workPath = new File( basePath.getPath() + File.separator
+                    + "work-" + tomcatConfig.getContext() + "-" + Integer.toString( tomcatConfig.getPort() ));
+            workPath.mkdir();
+            System.out.println( "using work directory: " + workPath.getAbsolutePath() );
+            return workPath;
+        }
+
+        System.out.println( "cant locate user home directory" );
+        System.exit( -1 );
+        return null;
+    }
+
+    private static Object outAndExit(final String output) {
+        System.out.println(output);
+        System.exit( -1 );
+        return null;
+    }
+}

+ 1 - 0
pom.xml

@@ -32,6 +32,7 @@
     <modules>
         <module>client</module>
         <module>server</module>
+        <module>onejar</module>
     </modules>
 
     <build>