http://git-wip-us.apache.org/repos/asf/tomee-site-generator/blob/972cc356/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
new file mode 100755
index 0000000..a479edc
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.tomee</groupId>
+  <artifactId>site</artifactId>
+  <version>1.0-SNAPSHOT</version>
+  <name>Apache TomEE :: WebSite NG</name>
+
+  <properties>
+    <tomee.version>7.0.3</tomee.version>
+    <jbake.http>false</jbake.http>
+    <jbake.pdf>false</jbake.pdf>
+
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.asciidoctor</groupId>
+      <artifactId>asciidoctorj-pdf</artifactId>
+      <version>1.5.0-alpha.11</version>
+    </dependency>
+    <dependency>
+      <groupId>org.asciidoctor</groupId>
+      <artifactId>asciidoctorj</artifactId>
+      <version>1.5.4</version>
+    </dependency>
+    <dependency>
+      <groupId>org.projectlombok</groupId>
+      <artifactId>lombok</artifactId>
+      <version>1.16.12</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-json_1.0_spec</artifactId>
+      <version>1.0-alpha-1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.johnzon</groupId>
+      <artifactId>johnzon-jaxrs</artifactId>
+      <version>0.9.5</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.cxf</groupId>
+      <artifactId>cxf-rt-rs-client</artifactId>
+      <version>3.1.8</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.tomee</groupId>
+      <artifactId>javaee-api</artifactId>
+      <version>7.0-1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.tomee</groupId>
+      <artifactId>tomee-embedded</artifactId>
+      <version>${tomee.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.jbake</groupId>
+      <artifactId>jbake-core</artifactId>
+      <version>2.4.0</version>
+      <exclusions>
+        <exclusion>
+          <groupId>org.slf4j</groupId>
+          <artifactId>jul-to-slf4j</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.groovy</groupId>
+      <artifactId>groovy</artifactId>
+      <version>2.3.11</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.groovy</groupId>
+      <artifactId>groovy-templates</artifactId>
+      <version>2.3.11</version>
+    </dependency>
+    <dependency>
+      <groupId>org.pegdown</groupId>
+      <artifactId>pegdown</artifactId>
+      <version>1.6.0</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>3.5.1</version>
+        <configuration>
+          <source>1.8</source>
+          <target>1.8</target>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>exec-maven-plugin</artifactId>
+        <version>1.5.0</version>
+        <executions>
+          <execution>
+            <id>tomee-site</id>
+            <phase>compile</phase>
+            <goals>
+              <goal>java</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <includeProjectDependencies>true</includeProjectDependencies>
+          <mainClass>org.apache.tomee.website.JBake</mainClass>
+          <arguments>
+            <argument>${project.basedir}/src/main/jbake/</argument>
+            
<argument>${project.build.directory}/${project.build.finalName}</argument>
+            <argument>${jbake.http}</argument>
+            <argument>${jbake.pdf}</argument>
+          </arguments>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/tomee-site-generator/blob/972cc356/src/main/java/org/apache/tomee/website/Contributors.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/tomee/website/Contributors.java 
b/src/main/java/org/apache/tomee/website/Contributors.java
new file mode 100755
index 0000000..fb4d0bf
--- /dev/null
+++ b/src/main/java/org/apache/tomee/website/Contributors.java
@@ -0,0 +1,222 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomee.website;
+
+import lombok.Builder;
+import lombok.Data;
+import org.apache.johnzon.jaxrs.JohnzonProvider;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Stream;
+
+import static java.util.Collections.emptyList;
+import static java.util.Optional.ofNullable;
+import static java.util.stream.Collectors.toList;
+
+public class Contributors {
+    private static final String GRAVATAR_BASE = "http://fr.gravatar.com/";;
+
+    private Contributors() {
+        // no-op
+    }
+
+    public static Contributor singleLoad(final WebTarget target, final String 
input) throws IOException {
+        try {
+            return ofNullable(loadGravatar(target, 
input)).orElse(loadStatic(input));
+        } catch (Exception e) {
+            e.printStackTrace();
+            return loadStatic(input);
+        }
+    }
+
+    public static Contributor loadStatic(final String input) {
+        final String[] strings = input.split(" *\\| *");
+        final String mail = strings[0].replaceAll("\\*$", "");
+        final boolean committer = strings[0].endsWith("*");
+        final String name = strings.length > 1 ? strings[1] : 
mail.replaceAll("@.*", "");
+        final String picture = strings.length > 2 ? strings[2] : 
"../img/noimg.png";
+        return Contributor.builder()
+                .name(name)
+                .id(mail)
+                .committer(committer)
+                .gravatar(picture)
+                .build();
+    }
+
+    public static Contributor loadGravatar(final WebTarget target, final 
String input) throws IOException {
+        final String[] strings = input.split(" *\\| *");
+        final boolean committer = strings[0].endsWith("*");
+        final String mail = committer ? strings[0].substring(0, 
strings[0].length() - 1) : strings[0];
+        final String hash = gravatarHash(mail);
+        final Response gravatar = target.path(hash + 
".json").request(MediaType.APPLICATION_JSON_TYPE).get();
+        if (gravatar.getStatus() != HttpsURLConnection.HTTP_OK) {
+            System.err.println("[ERROR] No gravatar for " + mail);
+            return null;
+        }
+        final Contributor contributor = 
ofNullable(gravatar.readEntity(Gravatar.class).getEntry())
+                .map(e -> e[0])
+                .map(e -> Contributor.builder()
+                        .id(e.getId())
+                        .name(
+                                ofNullable(e.getName())
+                                        .map(n -> 
ofNullable(n.getFormatted()).orElse(ofNullable(n.getGivenName()).orElse("") + 
ofNullable(n.getFamilyName()).orElse("")))
+                                        .orElseGet(() -> 
ofNullable(e.getDisplayName()).orElse(ofNullable(e.getPreferredUsername()).orElse(mail))))
+                        .description(e.getAboutMe())
+                        .link(
+                                Stream.concat(
+                                        ofNullable(e.getAccounts())
+                                                .map(a -> Stream.of(a).map(l 
-> 
Link.builder().name(l.getShortname()).url(l.getUrl()).build()).collect(toList()))
+                                                .orElse(emptyList()).stream(),
+                                        ofNullable(e.getUrls())
+                                                .map(a -> Stream.of(a).map(l 
-> 
Link.builder().name(l.getTitle()).url(l.getValue()).build()).collect(toList()))
+                                                .orElse(emptyList()).stream())
+                                        .collect(toList()))
+                        .gravatar("http://www.gravatar.com/avatar/"; + hash + 
"?s=140")
+                        .build())
+                .orElse(Contributor.builder().name(mail).id(mail).build());
+        contributor.setCommitter(committer);
+        ofNullable(contributor.getLink()).ifPresent(l -> Collections.sort(l, 
(o1, o2) -> o1.getName().compareTo(o2.getName())));
+        return contributor;
+    }
+
+    public static Collection<Contributor> load(final String contributorsList) 
throws IOException { // used in page.gsp
+        final WebTarget target = ClientBuilder.newClient().register(new 
JohnzonProvider()).target(GRAVATAR_BASE);
+        final List<Contributor> contributors = new ArrayList<>();
+        final ExecutorService es = Executors.newFixedThreadPool(16);
+        final String rawList = 
contributorsList.substring(contributorsList.indexOf("<pre>") + 
"<pre>".length(), contributorsList.indexOf("</pre>"));
+        try (final BufferedReader reader = new BufferedReader(new 
StringReader(rawList))) {
+            String line;
+            while ((line = reader.readLine()) != null) {
+                line = line.trim();
+                if (line.isEmpty() || line.startsWith("#")) {
+                    continue;
+                }
+                final String mail = line;
+                es.submit(() -> {
+                    Contributor contributor = null;
+                    try {
+                        contributor = singleLoad(target, mail);
+                    } catch (final IOException e) {
+                        throw new IllegalStateException(e);
+                    }
+                    if (contributor != null) {
+                        synchronized (contributors) {
+                            contributors.add(contributor);
+                        }
+                    }
+                });
+            }
+        }
+        es.shutdown();
+        try {
+            es.awaitTermination(30, TimeUnit.MINUTES);
+        } catch (final InterruptedException e) {
+            Thread.interrupted();
+            return Collections.emptyList();
+        }
+        Collections.sort(contributors, (o1, o2) -> o1.name.compareTo(o2.id));
+        return contributors;
+    }
+
+    private static String gravatarHash(final String mail) {
+        try {
+            final MessageDigest md = MessageDigest.getInstance("MD5");
+            byte[] cp1252s = md.digest(mail.getBytes("CP1252"));
+            final StringBuilder sb = new StringBuilder();
+            for (final byte anArray : cp1252s) {
+                sb.append(Integer.toHexString((anArray & 0xFF) | 
0x100).substring(1, 3));
+            }
+            return sb.toString();
+        } catch (final NoSuchAlgorithmException | UnsupportedEncodingException 
e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    @Data
+    @Builder
+    public static class Link {
+        private String name;
+        private String url;
+    }
+
+    @Data
+    @Builder
+    public static class Contributor {
+        private String id;
+        private boolean committer;
+        private String name;
+        private String description;
+        private String gravatar;
+        private List<Link> link;
+    }
+
+    @Data
+    public static class GravatarName {
+        private String formatted;
+        private String givenName;
+        private String familyName;
+    }
+
+    @Data
+    public static class GravatarUrl {
+        private String value;
+        private String title;
+    }
+
+    @Data
+    public static class GravatarAccount {
+        private String shortname;
+        private String url;
+    }
+
+    @Data
+    public static class Gravatar {
+        private GravatarEntry[] entry;
+    }
+
+    @Data
+    public static class GravatarEntry {
+        private String id;
+        private String hash;
+        private String aboutMe;
+        private String requestHash;
+        private String profileUrl;
+        private String preferredUsername;
+        private String thumbnailUrl;
+        private GravatarName name;
+        private GravatarUrl[] urls;
+        private GravatarAccount[] accounts;
+        private String displayName;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee-site-generator/blob/972cc356/src/main/java/org/apache/tomee/website/Downloads.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/tomee/website/Downloads.java 
b/src/main/java/org/apache/tomee/website/Downloads.java
new file mode 100755
index 0000000..cbb6e73
--- /dev/null
+++ b/src/main/java/org/apache/tomee/website/Downloads.java
@@ -0,0 +1,247 @@
+package org.apache.tomee.website;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.lang3.text.WordUtils;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Stream;
+
+import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME;
+import static java.util.Arrays.asList;
+import static java.util.Optional.ofNullable;
+import static java.util.stream.Collectors.toList;
+import static lombok.AccessLevel.PRIVATE;
+
+// regenerate when needed only, useless to do it for any site update
+@RequiredArgsConstructor(access = PRIVATE)
+public class Downloads {
+    private static final SAXParserFactory FACTORY = 
SAXParserFactory.newInstance();
+    private static final String MVN_BASE = 
"http://repo.maven.apache.org/maven2/";;
+    private static final long MEGA_RATIO = 1024 * 1024;
+
+    static {
+        FACTORY.setNamespaceAware(false);
+        FACTORY.setValidating(false);
+    }
+
+    public static void main(final String[] args) {
+        
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", 
"512");
+        Stream.of(
+                Stream.of("org/apache/openejb/openejb", 
"org/apache/tomee/tomee-project")
+                        .flatMap(Downloads::toVersions)
+                        .map(v -> v.extensions("zip"))
+                        .map(v -> v.classifiers("source-release")),
+                versionStream("apache-tomee")
+                        .map(v -> v.version.startsWith("1.") ?
+                                v.classifiers("plus", "plume", "webprofile", 
"jaxrs") : v.classifiers("plus", "plume", "webprofile"))
+                        .map(v -> v.extensions("tar.gz", "zip")),
+                versionStream("openejb-standalone")
+                        .map(v -> v.extensions("tar.gz", "zip")),
+                versionStream("tomee-webapp")
+                        .map(v -> v.extensions("war")),
+                versionStream("tomee-plus-webapp")
+                        .map(v -> v.extensions("war")),
+                versionStream("tomee-plume-webapp")
+                        .map(v -> v.extensions("war")))
+                .flatMap(s -> s)
+                .flatMap(Downloads::toDownloadable)
+                .parallel()
+                .map(Downloads::fillDownloadable)
+                .filter(Objects::nonNull /* skipped */)
+                .sorted((o1, o2) -> {
+                    final int nameComp = o1.name.compareTo(o2.name);
+                    if (nameComp != 0) {
+                        return nameComp;
+                    }
+
+                    final int versionComp = o2.version.compareTo(o1.version);
+                    if (versionComp != 0) {
+                        if (o2.version.startsWith(o1.version) && 
o2.version.contains("-M")) { // milestone
+                            return -1;
+                        }
+                        if (o1.version.startsWith(o2.version) && 
o1.version.contains("-M")) { // milestone
+                            return 1;
+                        }
+                        return versionComp;
+                    }
+
+                    final long dateComp = LocalDateTime.parse(o2.date, 
RFC_1123_DATE_TIME).toInstant(ZoneOffset.UTC).toEpochMilli()
+                            - LocalDateTime.parse(o1.date, 
RFC_1123_DATE_TIME).toInstant(ZoneOffset.UTC).toEpochMilli();
+                    if (dateComp != 0) {
+                        return (int) dateComp;
+                    }
+
+                    return o1.url.compareTo(o2.url);
+                })
+                .collect(toList())
+                .forEach(d ->
+                        System.out.println("" +
+                                "|" + d.name + (d.classifier.isEmpty() ? "" : 
(" " + d.classifier)) +
+                                "|" + d.version +
+                                "|" + d.date +
+                                "|" + d.size + " MB " +
+                                "|" + d.format +
+                                "| " + d.url + "[icon:download[] " + d.format 
+ "] " + d.sha1 + "[icon:download[] sha1] " + d.md5 + "[icon:download[] md5] " 
+ d.asc + "[icon:download[] asc]"));
+    }
+
+    private static Download fillDownloadable(final Download download) {
+        try {
+            final URL url = new URL(download.url);
+            final HttpURLConnection connection = 
HttpURLConnection.class.cast(url.openConnection());
+            connection.setConnectTimeout((int) TimeUnit.SECONDS.toMillis(30));
+            final int responseCode = connection.getResponseCode();
+            if (responseCode != HttpURLConnection.HTTP_OK) {
+                if (HttpURLConnection.HTTP_NOT_FOUND != responseCode) {
+                    System.err.println("Got " + responseCode + " for " + 
download.url);
+                }
+                return null;
+            }
+
+            
download.setDate(connection.getHeaderField("Last-Modified").replaceAll(" +", " 
"));
+            
download.setSize(toMega(ofNullable(connection.getHeaderField("Content-Length")).map(Long::parseLong).orElse(0L),
 ofNullable(connection.getHeaderField("Accept-Ranges")).orElse("bytes")));
+
+            connection.getInputStream().close();
+        } catch (final IOException e) {
+            e.printStackTrace();
+            return null;
+        }
+        return download;
+    }
+
+    private static long toMega(final long length, final String bytes) {
+        if (!"bytes".equalsIgnoreCase(bytes)) {
+            throw new IllegalArgumentException("Not handled unit: " + bytes);
+        }
+        return length / MEGA_RATIO;
+    }
+
+    private static Stream<Version> versionStream(final String artifactId) {
+        return Stream.of(artifactId)
+                .flatMap(s -> Stream.of("org/apache/tomee/" + s, 
"org/apache/openejb/" + s))
+                .flatMap(Downloads::toVersions);
+    }
+
+    private static Stream<Download> toDownloadable(final Version version) {
+        final String base = version.base;
+        final String artifactId = base.substring(base.lastIndexOf('/') + 1, 
base.length());
+        final String artifactBase = version.base + "/" + version.version + "/" 
+ artifactId + "-" + version.version;
+        return version.extensions.stream()
+                .flatMap(e -> (version.classifiers.isEmpty() ? Stream.of(new 
ArtifactDescription("", e)) : version.classifiers.stream().map(c -> new 
ArtifactDescription(c, e))))
+                .map(a -> toDownload(artifactId, a.classifier, 
version.version, a.extension, artifactBase + (a.classifier.isEmpty() ? '.' + 
a.extension : ('-' + a.classifier + '.' + a.extension))));
+    }
+
+    private static Download toDownload(final String artifactId, final String 
classifier, final String version, final String format, final String url) {
+        return new Download(
+                WordUtils.capitalize(artifactId.replace('-', ' 
')).replace("Openejb", "OpenEJB").replace("Tomee", "TomEE"),
+                classifier,
+                version,
+                format,
+                url,
+                url + ".md5",
+                url + ".sha1",
+                url + ".asc");
+    }
+
+    private static Stream<Version> toVersions(final String baseUrl) {
+        final QuickMvnMetadataParser handler = new QuickMvnMetadataParser();
+        final String base = MVN_BASE + baseUrl;
+        try (final InputStream stream = new URL(base + 
"/maven-metadata.xml").openStream()) {
+            final SAXParser parser = FACTORY.newSAXParser();
+            parser.parse(stream, handler);
+            return handler.foundVersions.stream().map(v -> new Version(base, 
v)).parallel();
+        } catch (final Exception e) {
+            e.printStackTrace();
+            return Stream.empty();
+        }
+    }
+
+    @AllArgsConstructor
+    public static class Version {
+        private final String base;
+        private final String version;
+        private final Collection<String> classifiers = new ArrayList<>();
+        private final Collection<String> extensions = new ArrayList<>();
+
+        private Version extensions(final String... values) {
+            extensions.addAll(asList(values));
+            return this;
+        }
+
+        private Version classifiers(final String... values) {
+            classifiers.addAll(asList(values));
+            return this;
+        }
+    }
+
+    @Data
+    public static class ArtifactDescription {
+        private final String classifier;
+        private final String extension;
+    }
+
+    @Data
+    public static class Download {
+        private final String name;
+        private final String classifier;
+        private final String version;
+        private final String format;
+        private final String url;
+        private final String md5;
+        private final String sha1;
+        private final String asc;
+        private String date;
+        private long size;
+    }
+
+    private static class QuickMvnMetadataParser extends DefaultHandler {
+        private boolean versioning = false;
+        private boolean versions = false;
+        private StringBuilder version;
+        private final Collection<String> foundVersions = new ArrayList<>();
+
+        @Override
+        public void startElement(final String uri, final String localName,
+                                 final String name, final Attributes 
attributes) throws SAXException {
+            if ("versioning".equalsIgnoreCase(name)) {
+                versioning = true;
+            } else if ("versions".equalsIgnoreCase(name)) {
+                versions = true;
+            } else if (versioning && versions && 
"version".equalsIgnoreCase(name)) {
+                version = new StringBuilder();
+            }
+        }
+
+        @Override
+        public void characters(final char[] ch, final int start, final int 
length) throws SAXException {
+            if (version != null) {
+                version.append(new String(ch, start, length));
+            }
+        }
+
+        public void endElement(final String uri, final String localName, final 
String name) throws SAXException {
+            if ("versioning".equalsIgnoreCase(name)) {
+                versioning = false;
+            } else if ("versions".equalsIgnoreCase(name)) {
+                versions = false;
+            } else if ("version".equalsIgnoreCase(name)) {
+                foundVersions.add(version.toString());
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee-site-generator/blob/972cc356/src/main/java/org/apache/tomee/website/Examples.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/tomee/website/Examples.java 
b/src/main/java/org/apache/tomee/website/Examples.java
new file mode 100755
index 0000000..efab3d5
--- /dev/null
+++ b/src/main/java/org/apache/tomee/website/Examples.java
@@ -0,0 +1,319 @@
+package org.apache.tomee.website;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.johnzon.jaxrs.JohnzonProvider;
+import org.apache.johnzon.mapper.JohnzonProperty;
+import org.apache.johnzon.mapper.MapperBuilder;
+
+import javax.ws.rs.ForbiddenException;
+import javax.ws.rs.NotFoundException;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Invocation;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.GenericType;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+import static java.util.Arrays.asList;
+import static java.util.Optional.ofNullable;
+import static java.util.stream.Collectors.toList;
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
+import static lombok.AccessLevel.PRIVATE;
+import static org.apache.commons.codec.binary.Base64.decodeBase64;
+
+@NoArgsConstructor(access = PRIVATE)
+public class Examples {
+    private static final String DEFAULT_README = "No README.md yet, be the 
first to contribute one!";
+
+    // don't load it for each page, would be pretty inefficient
+    private static final Map<String, Collection<Example>> CACHE = new 
TreeMap<>();
+    private static final String CACHE_FILE = "examples.cache";
+    private static final Collection<String> EXCLUDED_KEYWORDS = new 
HashSet<>(asList(
+            "with", "jvm", "preview", "demo", "to", "a", "access", "and", 
"app", "application", "auto", "basic", "bean", "by", "change", "complete",
+            "composer", "custom", "declared", "example", "handling", "in", 
"by", "change", "simple", "interface"));
+
+    public static void populateTree() {
+        final String date = new SimpleDateFormat("yyyy-MM-dd").format(new 
Date());
+        load();
+        CACHE.forEach((tag, examples) -> examples.forEach(e -> {
+            try (final Writer w = new 
FileWriter("src/main/jbake/content/examples/" + e.getName() + ".adoc")) {
+                w.write("= " + findTitle(e.getName(), e.getReadme()) + "\n" +
+                        ":jbake-date: " + date + "\n" +
+                        ":jbake-type: page\n" +
+                        ":jbake-tomeepdf:\n" +
+                        ":jbake-status: published\n\n" +
+                        "Example " + e.getName() + " can be browsed at " + 
e.getUrl() + "\n\n" +
+                        mdToAdoc(e.getReadme()));
+            } catch (final IOException ioe) {
+                throw new IllegalStateException(ioe);
+            }
+        }));
+    }
+
+    public static ExampleWrapper loadAll() {
+        load();
+        return new ExampleWrapper(CACHE, 
CACHE.values().stream().mapToInt(Collection::size).sum());
+    }
+
+    public static void load() {
+        if (!CACHE.isEmpty()) {
+            return;
+        }
+
+        final File cache = new File(CACHE_FILE);
+        if (cache.isFile()) {
+            System.out.println("Reading examples from cache, delete " + 
CACHE_FILE + " if you want to reload them");
+            try (final InputStream is = new FileInputStream(cache)) {
+                final ExampleWrapper wrapper = new 
MapperBuilder().build().readObject(is, ExampleWrapper.class);
+                CACHE.putAll(wrapper.getAll());
+            } catch (IOException e) {
+                throw new IllegalArgumentException(e);
+            }
+            return;
+        }
+
+        final Client client = ClientBuilder.newClient().register(new 
JohnzonProvider<>());
+        try {
+            final WebTarget github = client.target("https://api.github.com";);
+            final Invocation.Builder request = 
github.path("repos/apache/tomee/contents/examples").request(APPLICATION_JSON_TYPE);
+            final String auth = System.getProperty("github.auth");
+            if (auth != null) {
+                request.header("Authorization", auth);
+            }
+            request
+                    .get(new GenericType<Collection<GithubContentItem>>() {
+                    }).stream().filter(i -> "dir".equals(i.getType()))
+                    .parallel()
+                    .sorted((i1, i2) -> i1.getName().compareTo(i2.getName()))
+                    .map(i -> new Example(i.getName(), i.getHtmlUrl(), 
loadReadme(auth, github, i)))
+                    .forEach(example -> {
+                        final Collection<String> split = 
Stream.of(example.getName()
+                                .replace("application-composer", 
"applicationcomposer")
+                                .replace("configproperty", "config")
+                                .replace("descriptors", "descriptor")
+                                .replace("ejbs", "ejb")
+                                .replace("env-entry", "enventry")
+                                .replace("events", "event")
+                                .replace("interceptors", "interceptor")
+                                .split("-"))
+                                .filter(s -> !EXCLUDED_KEYWORDS.contains(s))
+                                .filter(s -> {
+                                    try {
+                                        Integer.parseInt(s);
+                                        return false;
+                                    } catch (final NumberFormatException nfe) {
+                                        return true;
+                                    }
+                                })
+                                .collect(toList());
+                        if (split.isEmpty()) {
+                            CACHE.computeIfAbsent("Unclassified", k -> new 
ArrayList<>()).add(example);
+                        } else {
+                            for (final String keyword : split) {
+                                CACHE.computeIfAbsent(keyword, k -> new 
ArrayList<>()).add(example);
+                            }
+                        }
+                    });
+
+            // debug stats
+            final int totalExamples = CACHE.size();
+            final long exampleMissingReadme = 
CACHE.values().stream().flatMap(Collection::stream).filter(e -> 
DEFAULT_README.equals(e.getReadme())).count();
+            System.out.println(exampleMissingReadme + "/" + totalExamples + " 
miss a README.md");
+            CACHE.values().stream().flatMap(Collection::stream).filter(e -> 
DEFAULT_README.equals(e.getReadme())).forEach(e -> System.out.println("  - " + 
e.getName()));
+
+            try (final OutputStream os = new FileOutputStream(CACHE_FILE)) {
+                new 
MapperBuilder().setPretty(true).build().writeObject(loadAll(), os);
+            } catch (final IOException e) {
+                throw new IllegalArgumentException(e);
+            }
+        } finally {
+            client.close();
+        }
+    }
+
+    private static String loadReadme(final String auth, final WebTarget 
github, final GithubContentItem i) {
+        try {
+            final Invocation.Builder request = 
github.path("repos/apache/tomee/contents/examples/{name}/README.md")
+                    .resolveTemplate("name", 
i.getName()).request(APPLICATION_JSON_TYPE);
+            if (auth != null) {
+                request.header("Authorization", auth);
+            }
+            return ofNullable(request
+                    .get(GithubContentItem.class)
+                    .getContent())
+                    .map(c -> new String(decodeBase64(c), 
StandardCharsets.UTF_8))
+                    .orElse(DEFAULT_README);
+        } catch (final NotFoundException wae) {
+            System.err.println(wae.getMessage() + " for the README.md of " + 
i.getName());
+            return DEFAULT_README;
+        } catch (final ForbiddenException wae) {
+            System.err.println("Can't retrieve examples, set 
-Dgithub.auth=.... to get a higher rate limit");
+            return DEFAULT_README;
+        }
+    }
+
+    private static String findTitle(final String name, final String readme) {
+        try (final BufferedReader reader = new BufferedReader(new 
StringReader(readme))) {
+            String line;
+            while ((line = reader.readLine()) != null) {
+                if (line.startsWith("Title: ")) {
+                    return line.substring("Title: ".length());
+                }
+            }
+        } catch (final IOException e) {
+            throw new IllegalStateException(e);
+        }
+        return name;
+    }
+
+    // quick cleanup of markdown syntax to adoc one used there
+    private static String mdToAdoc(final String s) {
+        final Pattern link = 
Pattern.compile("(.*)\\[([^\\]]*)\\]\\(([^\\)]*)\\)(.*)");
+
+        try (final StringWriter writer = new StringWriter();
+             final BufferedReader reader = new BufferedReader(new 
StringReader(s))) {
+            String line;
+            while ((line = reader.readLine()) != null) {
+                if (line.startsWith("Title: ")) {
+                    continue;
+                }
+                if (line.startsWith("#")) {
+                    for (int i = 0; i < line.length(); i++) {
+                        if (line.charAt(i) == '#') {
+                            writer.append('=');
+                        } else {
+                            writer.append(" ").append(line.substring(i));
+                            break;
+                        }
+                    }
+                } else if (line.startsWith("    package") || line.startsWith(" 
   import") || line.startsWith("    public ") || line.startsWith("    @")) { // 
java code
+                    writer.append("\n[source,java]\n----\n");
+                    writer.append(line.replaceFirst("    ", "")).append('\n');
+                    while ((line = reader.readLine()) != null) {
+                        writer.append(line.replaceFirst("    ", 
"")).append('\n');
+                        if ("    }".equals(line)) {
+                            writer.append("----\n");
+                            break;
+                        }
+                    }
+                } else if (line.startsWith("    <")) { // xml code
+                    writer.append("\n[source,xml]\n----\n");
+                    if (line.startsWith("    <?")) { // prolog
+                        writer.append(line.replaceFirst("    ", 
"")).append('\n');
+                        line = reader.readLine();
+                    }
+                    while (line != null && line.trim().isEmpty()) {
+                        line = reader.readLine();
+                    }
+                    if (line.trim().startsWith("<!--")) {
+                        if (line.contains("-->")) {
+                            writer.append(line.replaceFirst("    ", 
"")).append('\n');
+                        } else {
+                            do {
+                                writer.append(line.replaceFirst("    ", 
"")).append('\n');
+                            } while ((line = reader.readLine()) != null && 
!line.trim().equals("-->"));
+                            writer.append(line.replaceFirst("    ", 
"")).append('\n');
+                        }
+                        line = reader.readLine();
+                        while (line != null && line.trim().isEmpty()) {
+                            line = reader.readLine();
+                        }
+                    }
+
+                    if (line.trim().endsWith("/>")) {
+                        writer.append(line.replaceFirst("    ", 
"")).append('\n');
+                        writer.append("----\n");
+                    } else {
+                        final int space = line.indexOf(' ', 5);
+                        final String end = "</" + line.substring(5, space < 0 
? line.indexOf('>') : space) + ">";
+                        writer.append(line.replaceFirst("    ", 
"")).append('\n');
+                        while ((line = reader.readLine()) != null) {
+                            writer.append(line.replaceFirst("    ", 
"")).append('\n');
+                            if (end.equals(line.trim())) {
+                                writer.append("----\n");
+                                break;
+                            }
+                        }
+                    }
+                } else if (line.startsWith("    
-------------------------------------------------------")) { // run output
+                    writer.append("\n[source]\n----\n");
+                    writer.append(line.replaceFirst("    ", "")).append('\n');
+                    while ((line = reader.readLine()) != null) {
+                        writer.append(line.replaceFirst("    ", 
"")).append('\n');
+                        if (line.startsWith("    Tests run:") && 
!line.contains("Time elapsed:")) {
+                            writer.append("----\n");
+                            break;
+                        }
+                    }
+                } else if (line.startsWith(">")) {
+                    writer.append("\nNOTE: 
").append(line.substring(1)).append("\n");
+                } else {
+                    final Matcher matcher = link.matcher(line);
+                    if (matcher.matches()) {
+                        String l = matcher.group(3);
+                        if (l.startsWith("../") && l.endsWith("README.html")) 
{ // hack for old relative links
+                            l = l.substring("../".length(), l.length() - 
"/README.html".length()) + ".html";
+                        }
+                        
writer.append(matcher.group(1)).append("link:").append(l).append('[').append(matcher.group(2)).append(']').append(matcher.group(4));
+                    } else {
+                        writer.append(line);
+                    }
+                }
+                writer.append('\n');
+            }
+            return writer.toString();
+        } catch (final IOException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    public static void main(final String[] args) {
+        populateTree();
+    }
+
+    @Data
+    public static class ExampleWrapper {
+        private final Map<String, Collection<Example>> all;
+        private final int total;
+    }
+
+    @Data
+    public static class Example {
+        private final String name;
+        private final String url;
+        private final String readme;
+    }
+
+    @Data
+    public static class GithubContentItem {
+        private String name;
+        private String path;
+        private String type;
+        private String content;
+
+        @JohnzonProperty("html_url")
+        private String htmlUrl;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee-site-generator/blob/972cc356/src/main/java/org/apache/tomee/website/JBake.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/tomee/website/JBake.java 
b/src/main/java/org/apache/tomee/website/JBake.java
new file mode 100755
index 0000000..e4b288d
--- /dev/null
+++ b/src/main/java/org/apache/tomee/website/JBake.java
@@ -0,0 +1,181 @@
+package org.apache.tomee.website;
+
+import com.orientechnologies.orient.core.Orient;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.configuration.CompositeConfiguration;
+import org.apache.tomee.embedded.Configuration;
+import org.apache.tomee.embedded.Container;
+import org.jbake.app.ConfigUtil;
+import org.jbake.app.Oven;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.ClosedWatchServiceException;
+import java.nio.file.Path;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.util.Scanner;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Stream;
+
+import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
+import static lombok.AccessLevel.PRIVATE;
+
+@RequiredArgsConstructor(access = PRIVATE)
+public class JBake {
+    public static void main(final String[] args) throws Exception {
+        
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", 
"64"); // try to have parallelStream better than default
+
+        final File source = args == null || args.length < 1 ? new 
File("src/main/jbake") : new File(args[0]);
+        final File pdfSource = new File(source, "content");
+        final File destination = args == null || args.length < 2 ? new 
File("target/site-tmp") : new File(args[1]);
+        final boolean startHttp = args == null || args.length < 2 || 
Boolean.parseBoolean(args[2]); // by default we dev
+        final boolean skipPdf = args == null || args.length < 3 || 
Boolean.parseBoolean(args[3]); // by default...too slow sorry
+
+        final Runnable build = () -> {
+            System.out.println("Building TomEE website in " + destination);
+            final Orient orient = Orient.instance();
+            try {
+                orient.startup();
+
+                final Oven oven = new Oven(source, destination, new 
CompositeConfiguration() {{
+                    addConfiguration(ConfigUtil.load(source));
+                }}, true);
+                oven.setupPaths();
+
+                System.out.println("  > baking");
+                oven.bake();
+
+                if (!skipPdf) {
+                    System.out.println("  > pdfifying");
+                    PDFify.generatePdf(pdfSource, destination);
+                }
+
+                System.out.println("  > done :)");
+            } catch (final Exception e) {
+                e.printStackTrace();
+            } finally {
+                orient.shutdown();
+            }
+        };
+
+        build.run();
+        if (startHttp) {
+            final Path watched = source.toPath();
+            final WatchService watchService = 
watched.getFileSystem().newWatchService();
+            watched.register(watchService, ENTRY_CREATE, ENTRY_DELETE, 
ENTRY_MODIFY);
+            final AtomicBoolean run = new AtomicBoolean(true);
+            final AtomicLong render = new AtomicLong(-1);
+            final Thread renderingThread = new Thread() {
+                {
+                    setName("jbake-renderer");
+                }
+
+                @Override
+                public void run() {
+                    long last = System.currentTimeMillis();
+                    while (run.get()) {
+                        if (render.get() > last) {
+                            last = System.currentTimeMillis();
+                            try {
+                                build.run();
+                            } catch (final Throwable oops) {
+                                oops.printStackTrace();
+                            }
+                        }
+                        try {
+                            sleep(TimeUnit.SECONDS.toMillis(1));
+                        } catch (final InterruptedException e) {
+                            Thread.interrupted();
+                            break;
+                        }
+                    }
+                }
+            };
+            final Thread watcherThread = new Thread() {
+                {
+                    setName("jbake-file-watcher");
+                }
+
+                @Override
+                public void run() {
+                    while (run.get()) {
+                        try {
+                            final WatchKey key = watchService.poll(1, 
TimeUnit.SECONDS);
+                            if (key == null) {
+                                continue;
+                            }
+
+                            for (final WatchEvent<?> event : key.pollEvents()) 
{
+                                final WatchEvent.Kind<?> kind = event.kind();
+                                if (kind != ENTRY_CREATE && kind != 
ENTRY_DELETE && kind != ENTRY_MODIFY) {
+                                    continue; // unlikely but better to 
protect ourself
+                                }
+
+                                final Path updatedPath = 
Path.class.cast(event.context());
+                                if (kind == ENTRY_DELETE || 
updatedPath.toFile().isFile()) {
+                                    final String path = updatedPath.toString();
+                                    if (!path.contains("___jb") && 
!path.endsWith("~")) {
+                                        render.set(System.currentTimeMillis());
+                                    }
+                                }
+                            }
+                            key.reset();
+                        } catch (final InterruptedException e) {
+                            Thread.interrupted();
+                            run.compareAndSet(true, false);
+                        } catch (final ClosedWatchServiceException cwse) {
+                            if (!run.get()) {
+                                throw new IllegalStateException(cwse);
+                            }
+                        }
+                    }
+                }
+            };
+
+            renderingThread.start();
+            watcherThread.start();
+
+            final Runnable onQuit = () -> {
+                run.compareAndSet(true, false);
+                Stream.of(watcherThread, renderingThread).forEach(thread -> {
+                    try {
+                        thread.join();
+                    } catch (final InterruptedException e) {
+                        Thread.interrupted();
+                    }
+                });
+                try {
+                    watchService.close();
+                } catch (final IOException ioe) {
+                    // not important
+                }
+            };
+
+            try (final Container container = new Container(new Configuration() 
{{
+                setWebResourceCached(false);
+                property("openejb.additional.exclude", "logback,jbake");
+            }}).deployClasspathAsWebApp(null, destination)) {
+                System.out.println("Started on http://localhost:"; + 
container.getConfiguration().getHttpPort());
+
+                final Scanner console = new Scanner(System.in);
+                String cmd;
+                while (((cmd = console.nextLine())) != null) {
+                    if ("quit".equals(cmd)) {
+                        return;
+                    } else if ("r".equals(cmd) || "rebuild".equals(cmd) || 
"build".equals(cmd) || "b".equals(cmd)) {
+                        render.set(System.currentTimeMillis());
+                    } else {
+                        System.err.println("Ignoring " + cmd + ", please use 
'build' or 'quit'");
+                    }
+                }
+            }
+            onQuit.run();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee-site-generator/blob/972cc356/src/main/java/org/apache/tomee/website/PDFify.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/tomee/website/PDFify.java 
b/src/main/java/org/apache/tomee/website/PDFify.java
new file mode 100755
index 0000000..b0a2a41
--- /dev/null
+++ b/src/main/java/org/apache/tomee/website/PDFify.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomee.website;
+
+import lombok.RequiredArgsConstructor;
+import org.asciidoctor.Asciidoctor;
+import org.asciidoctor.AttributesBuilder;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import static lombok.AccessLevel.PRIVATE;
+import static org.asciidoctor.OptionsBuilder.options;
+
+@RequiredArgsConstructor(access = PRIVATE)
+public class PDFify {
+    public static void generatePdf(final File from, final File targetBase) 
throws IOException {
+        final Path sourceBase = from.toPath();
+        final Asciidoctor asciidoctor = Asciidoctor.Factory.create();
+        final ExecutorService pool = Executors.newFixedThreadPool(16);
+        Files.walkFileTree(sourceBase, new SimpleFileVisitor<Path>() {
+            @Override
+            public FileVisitResult visitFile(final Path file, final 
BasicFileAttributes attrs) throws IOException {
+                final String fileName = file.getFileName().toString();
+                if (fileName.endsWith(".adoc")) {
+                    pool.submit(() -> {
+                        final String path = 
sourceBase.relativize(file).toString();
+                        final File target = new File(targetBase, 
path.substring(0, path.length() - "adoc".length()) + "pdf");
+                        final File asFile = file.toFile();
+                        final Map<String, Object> attributes = 
asciidoctor.readDocumentHeader(asFile).getAttributes();
+                        // if we generate the PDF link we need to create the 
PDF excepted if it is expected to be manual
+                        if (attributes.containsKey("jbake-tomeepdf") && 
!attributes.containsKey("jbake-tomeepdf-manual")) {
+                            asciidoctor.convertFile(
+                                    asFile,
+                                    options().docType("article")
+                                            .backend
+                                            ("pdf")
+                                    
.attributes(AttributesBuilder.attributes().attribute("source-highlighter", 
"coderay")).toFile(target).get());
+                            System.out.println("Generated " + target);
+                        }
+                    });
+                }
+                return super.visitFile(file, attrs);
+            }
+        });
+        pool.shutdown();
+        try {
+            pool.awaitTermination(1, TimeUnit.HOURS);
+        } catch (final InterruptedException e) {
+            Thread.interrupted();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee-site-generator/blob/972cc356/src/main/java/org/apache/tomee/website/ServiceJarHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/tomee/website/ServiceJarHelper.java 
b/src/main/java/org/apache/tomee/website/ServiceJarHelper.java
new file mode 100755
index 0000000..135d803
--- /dev/null
+++ b/src/main/java/org/apache/tomee/website/ServiceJarHelper.java
@@ -0,0 +1,192 @@
+package org.apache.tomee.website;
+
+import org.apache.openejb.OpenEJBException;
+import org.apache.openejb.config.sys.JaxbOpenejb;
+import org.apache.openejb.config.sys.ServiceProvider;
+import org.apache.openejb.config.sys.ServicesJar;
+import org.apache.openejb.util.SuperProperties;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+// will stdout some doc from service-jar.xml
+// we could generate it in a template but will likely be manually updated
+// so using it as a kick off only
+public class ServiceJarHelper {
+    public static void main(final String[] args) throws Exception { // based 
on org.apache.openejb.config.sys.WikiGenerator
+        System.out.println();
+        System.out.println();
+        System.out.println("WARNING");
+        System.out.println("WARNING");
+        System.out.println("WARNING");
+        System.out.println("WARNING these generated contents are generally 
modified manually to enrich them");
+        System.out.println("WARNING don't overwrite the pages without checking 
you are losing or not any information");
+        System.out.println("WARNING");
+        System.out.println("WARNING");
+        System.out.println("WARNING");
+        System.out.println();
+        System.out.println();
+        new ServiceJarHelper("org.apache.openejb", new 
PrintWriter(System.out), true).generate();
+    }
+
+    private final ServicesJar servicesJar;
+    private final PrintWriter out;
+    private final boolean resources;
+
+    public ServiceJarHelper(final String providerName, final PrintWriter 
printWriter, final boolean resources) throws OpenEJBException {
+        this.servicesJar = JaxbOpenejb.readServicesJar(providerName);
+        this.out = printWriter;
+        this.resources = resources;
+    }
+
+    public void generate() throws Exception {
+        // generate containers
+        final List<ServiceProvider> serviceProvider = 
servicesJar.getServiceProvider();
+        if (!resources) {
+            Collections.sort(serviceProvider, new 
Comparator<ServiceProvider>() {
+                @Override
+                public int compare(final ServiceProvider o1, final 
ServiceProvider o2) {
+                    return grade(o2) - grade(o1);
+                }
+
+                private int grade(final ServiceProvider i) {
+                    final String name = i.getClassName();
+                    if (name.contains("stateless")) {
+                        return 10;
+                    }
+                    if (name.contains("stateful")) {
+                        return 9;
+                    }
+                    if (name.contains("singleton")) {
+                        return 8;
+                    }
+                    if (name.contains("mdb")) {
+                        return 7;
+                    }
+                    if (name.contains("managed")) {
+                        return 6;
+                    }
+                    return 0;
+                }
+            });
+
+            for (final ServiceProvider provider : serviceProvider) {
+                if ("Container".equals(provider.getService())) {
+                    generateService(provider);
+                }
+            }
+        } else {
+
+            final List<String> seen = new ArrayList<>();
+            for (final ServiceProvider provider : 
servicesJar.getServiceProvider()) {
+                if ("Resource".equals(provider.getService())) {
+
+                    if (seen.containsAll(provider.getTypes())) {
+                        continue;
+                    }
+
+                    generateService(provider);
+
+                    seen.addAll(provider.getTypes());
+                }
+            }
+        }
+        out.println();
+        out.flush();
+    }
+
+    private void generateService(final ServiceProvider provider) {
+        final Map<String, String> defaults = new LinkedHashMap<>();
+        final Map<String, String> comments = new LinkedHashMap<>();
+
+        final SuperProperties properties = (SuperProperties) 
provider.getProperties();
+        if (!properties.isEmpty()) {
+            for (final Object key : properties.keySet()) {
+                if (key instanceof String) {
+                    final String name = (String) key;
+                    if ("SkipImplicitAttributes".equals(name)) {
+                        continue;
+                    }
+
+                    final Map<String, String> attributes = 
properties.getAttributes(name);
+
+                    if (attributes.containsKey("hidden")) {
+                        continue;
+                    }
+
+                    final String value = properties.getProperty(name);
+
+                    String comment = properties.getComment(name);
+                    comment = scrubText(comment);
+                    if (comment.isEmpty()) {
+                        comment = "FIXME";
+                    }
+
+                    defaults.put(name, String.valueOf(value));
+                    comments.put(name, comment);
+                }
+            }
+        }
+
+        final String type = provider.getTypes().get(0);
+        out.println("=== " + type);
+        out.println();
+        out.println("Declarable in tomee.xml via");
+        out.println();
+        out.println("[source,xml]");
+        out.println("----");
+        out.print("<" + provider.getService() + " id=\"Foo\" type=\"" + type + 
"\"");
+        if (defaults.isEmpty()) {
+            out.println(" />");
+        } else {
+            out.println(">");
+            for (final Map.Entry<String, String> entry : defaults.entrySet()) {
+                out.print("    ");
+                out.print(entry.getKey());
+                out.print(" = ");
+                out.println(entry.getValue());
+            }
+            out.println("</" + provider.getService() + ">");
+        }
+        out.println("----");
+        out.println();
+        out.println("Declarable in properties via");
+        out.println();
+        out.println("[source,properties]");
+        out.println("----");
+        out.println("Foo = new://" + provider.getService() + "?type=" + type);
+        for (final Map.Entry<String, String> entry : defaults.entrySet()) {
+            out.print("Foo.");
+            out.print(entry.getKey());
+            out.print(" = ");
+            out.println(entry.getValue());
+        }
+        out.println("----");
+        out.println();
+
+        if (!properties.isEmpty()) {
+            out.println("==== Configuration");
+            out.println();
+            for (final Map.Entry<String, String> entry : comments.entrySet()) {
+                out.println("===== " + entry.getKey());
+                out.println();
+                out.println(entry.getValue());
+                out.println();
+            }
+        }
+
+        out.println();
+    }
+
+    private String scrubText(String text) {
+        if (text == null) {
+            text = "";
+        }
+        return text;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee-site-generator/blob/972cc356/src/main/java/org/slf4j/bridge/SLF4JBridgeHandler.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/slf4j/bridge/SLF4JBridgeHandler.java 
b/src/main/java/org/slf4j/bridge/SLF4JBridgeHandler.java
new file mode 100755
index 0000000..03b8ead
--- /dev/null
+++ b/src/main/java/org/slf4j/bridge/SLF4JBridgeHandler.java
@@ -0,0 +1,7 @@
+package org.slf4j.bridge;
+
+// dep of org.jbake.app.Oven but we don't want the bridge there
+public class SLF4JBridgeHandler {
+    public static void removeHandlersForRootLogger(){}
+    public static void install() {}
+}

http://git-wip-us.apache.org/repos/asf/tomee-site-generator/blob/972cc356/src/main/jbake/assets/bash
----------------------------------------------------------------------
diff --git a/src/main/jbake/assets/bash b/src/main/jbake/assets/bash
new file mode 100755
index 0000000..084b07c
--- /dev/null
+++ b/src/main/jbake/assets/bash
@@ -0,0 +1,147 @@
+#! /bin/bash
+
+#
+# This script will download and install tomee
+# in the user home executing the command
+#
+
+# "exposed" variables
+INSTALL_DIR=~/apache-tomee
+TOMEE_VERSION=7.0.0-M3
+TOMEE_CLASSIFIER=webprofile
+
+set -e
+set -u
+
+# a single stream is enough
+exec 1>&2
+
+# Find Java
+if type -p java; then
+    _java=java
+elif [ -n "$JAVA_HOME" -a -x "$JAVA_HOME/bin/java" ];  then   
+    _java="$JAVA_HOME/bin/java"
+else
+    echo "Java not found . Please install java. Aborting"
+    exit 1
+fi
+
+# Targets JavaEE 7 so java 7 at least
+if [ "$_java" ]; then
+    version=$("$_java" -version 2>&1 | awk -F '"' '/version/ {print $2}')
+    if [ "$version" \< "1.7" ]; then           
+        echo "JDK Version is less than 1.7 . TomEE $TOMEE_VERSION requires JDK 
7+ . Aborting."
+        exit 1
+    fi
+fi
+
+TMP_DIR="$INSTALL_DIR/install"
+TMP_CONF_DIR="$INSTALL_DIR/install_conf"
+TMP_WEBAPPS_DIR="$INSTALL_DIR/install_webapps"
+TMP_APPS_DIR="$INSTALL_DIR/install_apps"
+
+# save existing configuration
+if [ -d "$INSTALL_DIR" ]; then
+    echo "Saving previous installation state."
+
+    rm -rf "$TMP_CONF_DIR" "$TMP_WEBAPPS_DIR" "$TMP_APPS_DIR"
+    mkdir -p "$TMP_CONF_DIR" "$TMP_WEBAPPS_DIR" "$TMP_APPS_DIR"
+
+    tomee_base="$INSTALL_DIR/apache-tomee-$TOMEE_CLASSIFIER-$TOMEE_VERSION"
+    cp -r "$tomee_base/conf/." "$TMP_CONF_DIR"
+    cp -r "$tomee_base/webapps/." "$TMP_WEBAPPS_DIR"
+    if [ -d "$tomee_base/apps" ]; then
+        cp -r "$tomee_base/apps/." "$TMP_APPS_DIR"
+    fi
+
+    # remove distribution webapp to use new ones
+    rm -rf "$TMP_WEBAPPS_DIR/ROOT" "$TMP_WEBAPPS_DIR/docs" 
"$TMP_WEBAPPS_DIR/manager" "$TMP_WEBAPPS_DIR/host-manager"
+fi
+
+# get the new binaries
+rm -rf "$INSTALL_DIR" "$TMP_DIR"
+mkdir -p "$INSTALL_DIR" "$TMP_DIR"
+
+DOWNLOAD_LINK="http://repo.maven.apache.org/maven2/org/apache/tomee/apache-tomee/$TOMEE_VERSION/apache-tomee-$TOMEE_VERSION-$TOMEE_CLASSIFIER.zip";
+DOWNLOAD_ZIP="$TMP_DIR/tomee.zip"
+echo "Downloading TomEE $TOMEE_VERSION from $DOWNLOAD_LINK"
+curl --location --fail --progress-bar $DOWNLOAD_LINK > "$DOWNLOAD_ZIP"
+
+test -f "$DOWNLOAD_ZIP"
+
+echo "Extracting TomEE $TOMEE_VERSION"
+unzip "$DOWNLOAD_ZIP" -d "$INSTALL_DIR"
+TOMEE_BASE="$INSTALL_DIR/apache-tomee-$TOMEE_CLASSIFIER-$TOMEE_VERSION"
+test -x "$TOMEE_BASE"
+
+# restore configuration
+if [ -d "$TMP_CONF_DIR" ]; then
+    echo "Restoring previous installation state."
+    cp -r "$TMP_CONF_DIR" "$TOMEE_BASE/conf"
+    cp -r "$TMP_WEBAPPS_DIR" "$TOMEE_BASE/webapps"
+    cp -r "$TMP_APPS_DIR" "$TOMEE_BASE/apps"
+    rm -rf "$TMP_CONF_DIR" "$TMP_WEBAPPS_DIR" "$TMP_APPS_DIR"
+else
+    echo "No state to restore"
+fi
+rm -rf "$TMP_DIR"
+
+echo "TomEE $TOMEE_VERSION is now installed in directory $TOMEE_BASE."
+
+# create the profile script (vars)
+TOMEE_PROFILE=~/.tomee.profile
+if [ -f "$TOMEE_PROFILE" ]; then
+    rm -rf "$TOMEE_PROFILE"
+fi
+touch "$TOMEE_PROFILE"
+echo "export CATALINA_HOME="$TOMEE_BASE"" >> "$TOMEE_PROFILE"
+echo "export CATALINA_BASE="$TOMEE_BASE"" >> "$TOMEE_PROFILE"
+echo "# To add tomcat scripts to the path uncomment next line" >> 
"$TOMEE_PROFILE"
+echo "# export PATH="\$PATH:\$CATALINA_HOME/bin"" >> "$TOMEE_PROFILE"
+# some alternative commands, mainly to limit side effects of cygwin (wrong 
paths)
+echo "alias tomee-base='cd $TOMEE_BASE'" >> "$TOMEE_PROFILE"
+echo "alias tomee-run='cd $TOMEE_BASE && ./bin/catalina.sh run && cd -'" >> 
"$TOMEE_PROFILE"
+echo "alias tomee-start='cd $TOMEE_BASE && ./bin/catalina.sh start && cd -'" 
>> "$TOMEE_PROFILE"
+echo "alias tomee-stop='cd $TOMEE_BASE && ./bin/catalina.sh stop && cd -'" >> 
"$TOMEE_PROFILE"
+
+# make it immediate
+source "$TOMEE_PROFILE"
+
+# add it to the profile file whatever it is,
+# if they source themself it would reload env variable which is ok
+for f in ".bash_profile" ".bashrc" ".profile"; do
+    if [ -f ~/$f ];then
+        if grep "$TOMEE_PROFILE" ~/$f > /dev/null; then
+           echo "$TOMEE_PROFILE already sourced in $f"
+        else
+            echo source "$TOMEE_PROFILE" >> ~/$f
+        fi
+    fi
+done
+
+# Finally dump a small getting started
+echo ""
+echo ""
+echo "Get started:"
+echo "------------"
+echo ""
+echo ""
+echo "start in blocking mode TomEE - located in $TOMEE_BASE"
+echo "me@local:~ $ tomee-run"
+echo "..."
+echo "Ctrl+C"
+echo ""
+echo "start and forget - located in $TOMEE_BASE"
+echo "me@local:~ $ tomee-start"
+echo ""
+echo "..."
+echo "And stop it"
+echo "me@local:~ $ tomee-stop"
+echo ""
+echo " To deploy quickly an application drop it in $TOMEE_BASE/webapps and 
restart."
+echo "You can configure TomEE in $TOMEE_BASE/conf/ folder or in 
~/.openejb/system.properties."
+echo ""
+echo "You can use tomee-base command to directly go in $TOMEE_BASE"
+echo ""
+echo "Learn more on http://tomee.apache.org";
+echo ""

Reply via email to