From 061703ed669125a15254a71cc121ab0213e572f9 Mon Sep 17 00:00:00 2001 From: Alasdair Nottingham Date: Wed, 29 Apr 2020 22:10:57 -0400 Subject: [PATCH 1/3] Make latestVersion.js update without restart Fixes #1616 Currently the LatestVersion servlet doesn't correctly show an new build without a server restart so this fix aims to resolve that. The fix uses CDI events to notify the change. This necessetated the following changes: 1. BuildData is now a CDI beans which means using setter and getters for JSON-B. 2. BuildData now fires an event if the BuildType is a release. 3. The LatestVersion servlet now observes the event emitted by BuildData 4. The AtomicReference storing the latestVersion.js is now static since CDI events create random new instances for notification. 5. DHEBuildParser now has BuildData injected. 6. Written a test using MicroShed Testing and MockServer to support the updates. This new test won't pass with liberty dev mode though. Not quite sure how to resolve that at this time. 7. Added a pre destroy method to cancel the scheduled futures on shutdown. This means if using dev mode we correctly tidy up when in dev mode rather than relying on Liberty to do it. 8. Renamed the current Dockerfile to Dockerfile blogs since it is there to support building and editing the blog posts 9. Created a new Dockerfile that contains the website code. 10. Added catch blocks for JAX-RS RuntimeExceptions which will prevent retries working. --- .dockerignore | 2 + Dockerfile | 93 +----------- Dockerfile-blogs | 92 ++++++++++++ pom.xml | 68 +++++++-- .../io/openliberty/website/BuildsManager.java | 4 +- .../io/openliberty/website/LatestVersion.java | 37 +++-- .../website/OpenLibertyEndpoint.java | 4 +- .../openliberty/website/data/BuildData.java | 50 ++++++- .../openliberty/website/data/BuildType.java | 19 ++- .../website/dheclient/DHEBuildParser.java | 137 +++++++++++------- .../website/events/RuntimeRelease.java | 25 ++++ src/main/wlp/server.xml | 1 + .../website/BuildsManagerTest.java | 13 +- .../website/data/LastUpdateTest.java | 2 +- .../dheclient/DHEBuildsParserTest.java | 19 +-- .../website/it/MockDHEContainer.java | 104 +++++++++++++ .../website/it/OpenLibertyEndpointIT.java | 97 +++++++++++++ 17 files changed, 567 insertions(+), 200 deletions(-) create mode 100644 .dockerignore mode change 100755 => 100644 Dockerfile create mode 100755 Dockerfile-blogs create mode 100644 src/main/java/io/openliberty/website/events/RuntimeRelease.java create mode 100644 src/test/java/io/openliberty/website/it/MockDHEContainer.java create mode 100644 src/test/java/io/openliberty/website/it/OpenLibertyEndpointIT.java diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..422138267c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +target/ +!target/*.war \ No newline at end of file diff --git a/Dockerfile b/Dockerfile old mode 100755 new mode 100644 index e8978fd157..1501950a4a --- a/Dockerfile +++ b/Dockerfile @@ -1,92 +1,7 @@ -# Created by laura_cowen@uk.ibm.com, Twitter/GitHub/Docker username: @lauracowen -# 2017-11-02 -# Updated Oct. 2018 by Kin Ueng -# Installing and running Jekyll based on: based on https://blog.codeship.com/a-beginners-guide-to-the-dockerfile/ -# NodeJS and NPM sections based on: https://gist.github.com/remarkablemark/aacf14c29b3f01d6900d13137b21db3a +FROM open-liberty:kernel -# The purpose of this dockerfile is to run your Jekyll website so you don't have to install Jekyll -# and all of Jekyll's pre-requisite software. -# You can view the site in a browser on your local (host) machine (at http://0.0.0.0:4000). -# You can then modify website source files on your local (host) machine. -# When you save a changed file, the changes are automatically rebuilt by Jekyll in the container and you can almost immediately -# see the changes when you refresh your browser. - -# To build this image, from the directory that contains this Dockerfile: -# docker build --tag lauracowen/jekyll . -# -# To run a container: -# docker run --name jekyll -it -d -p 4000:4000 -v :/home/jekyll lauracowen/jekyll - -# Use the official Ruby image as a parent image -FROM ruby:latest - -# INSTALL NODEJS AND NPM (it's a dependency of something in the Jekyll setup) - -# replace shell with bash so we can source files -RUN rm /bin/sh && ln -s /bin/bash /bin/sh - -# update the repository sources list -# and install dependencies -RUN apt-get update \ - && apt-get install -y curl \ - && apt-get -y autoclean - -# nvm environment variables -ENV NVM_DIR /usr/local/nvm -ENV NODE_VERSION 9.0.0 - -# install nvm -# https://github.com/creationix/nvm#install-script -RUN curl --silent -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.2/install.sh | bash - -# install node and npm -RUN source $NVM_DIR/nvm.sh \ - && nvm install $NODE_VERSION \ - && nvm alias default $NODE_VERSION \ - && nvm use default - -# add node and npm to path so the commands are available -ENV NODE_PATH $NVM_DIR/v$NODE_VERSION/lib/node_modules -ENV PATH $NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH - -# confirm installation -RUN node -v -RUN npm -v - -# INSTALLING AND RUNNING JEKYLL - -# create a user and group for Jekyll, set appropriate permissions, install the Jekyll gem -RUN mkdir -p /home/jekyll \ - && groupadd -rg 1000 jekyll \ - && useradd -rg jekyll -u 1000 -d /home/jekyll jekyll \ - && chown jekyll:jekyll /home/jekyll - -# Create a mount point where Docker can access the source files on my local system (host system) -VOLUME /home/jekyll - -# Set the working directory -WORKDIR /home/jekyll - -# openliberty.io gem dependencies -COPY ./scripts /home/jekyll/scripts -RUN scripts/build_gem_dependencies.sh - -# openliberty.io custom gems -COPY ./gems /home/jekyll/gems -RUN pushd gems/ol-asciidoc \ - && gem build ol-asciidoc.gemspec \ - && gem install ol-asciidoc-0.0.1.gem \ - && popd - -RUN pushd gems/ol-target-blank \ - && gem build ol-target-blank.gemspec \ - && gem install ol-target-blank-0.0.1.gem \ - && popd - -# Serve the site -ENTRYPOINT ["bash", "./scripts/jekyll_serve_dev.sh"] - -# Make port 4000 available to the world outside this container -EXPOSE 4000 +ENV SEC_TLS_TRUSTDEFAULTCERTS true +COPY src/main/wlp/server.xml /config/server.xml +COPY target/openliberty.war /config/dropins/openliberty.war diff --git a/Dockerfile-blogs b/Dockerfile-blogs new file mode 100755 index 0000000000..e8978fd157 --- /dev/null +++ b/Dockerfile-blogs @@ -0,0 +1,92 @@ +# Created by laura_cowen@uk.ibm.com, Twitter/GitHub/Docker username: @lauracowen +# 2017-11-02 +# Updated Oct. 2018 by Kin Ueng +# Installing and running Jekyll based on: based on https://blog.codeship.com/a-beginners-guide-to-the-dockerfile/ +# NodeJS and NPM sections based on: https://gist.github.com/remarkablemark/aacf14c29b3f01d6900d13137b21db3a + +# The purpose of this dockerfile is to run your Jekyll website so you don't have to install Jekyll +# and all of Jekyll's pre-requisite software. +# You can view the site in a browser on your local (host) machine (at http://0.0.0.0:4000). +# You can then modify website source files on your local (host) machine. +# When you save a changed file, the changes are automatically rebuilt by Jekyll in the container and you can almost immediately +# see the changes when you refresh your browser. + +# To build this image, from the directory that contains this Dockerfile: +# docker build --tag lauracowen/jekyll . +# +# To run a container: +# docker run --name jekyll -it -d -p 4000:4000 -v :/home/jekyll lauracowen/jekyll + +# Use the official Ruby image as a parent image +FROM ruby:latest + +# INSTALL NODEJS AND NPM (it's a dependency of something in the Jekyll setup) + +# replace shell with bash so we can source files +RUN rm /bin/sh && ln -s /bin/bash /bin/sh + +# update the repository sources list +# and install dependencies +RUN apt-get update \ + && apt-get install -y curl \ + && apt-get -y autoclean + +# nvm environment variables +ENV NVM_DIR /usr/local/nvm +ENV NODE_VERSION 9.0.0 + +# install nvm +# https://github.com/creationix/nvm#install-script +RUN curl --silent -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.2/install.sh | bash + +# install node and npm +RUN source $NVM_DIR/nvm.sh \ + && nvm install $NODE_VERSION \ + && nvm alias default $NODE_VERSION \ + && nvm use default + +# add node and npm to path so the commands are available +ENV NODE_PATH $NVM_DIR/v$NODE_VERSION/lib/node_modules +ENV PATH $NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH + +# confirm installation +RUN node -v +RUN npm -v + +# INSTALLING AND RUNNING JEKYLL + +# create a user and group for Jekyll, set appropriate permissions, install the Jekyll gem +RUN mkdir -p /home/jekyll \ + && groupadd -rg 1000 jekyll \ + && useradd -rg jekyll -u 1000 -d /home/jekyll jekyll \ + && chown jekyll:jekyll /home/jekyll + +# Create a mount point where Docker can access the source files on my local system (host system) +VOLUME /home/jekyll + +# Set the working directory +WORKDIR /home/jekyll + +# openliberty.io gem dependencies +COPY ./scripts /home/jekyll/scripts +RUN scripts/build_gem_dependencies.sh + +# openliberty.io custom gems +COPY ./gems /home/jekyll/gems +RUN pushd gems/ol-asciidoc \ + && gem build ol-asciidoc.gemspec \ + && gem install ol-asciidoc-0.0.1.gem \ + && popd + +RUN pushd gems/ol-target-blank \ + && gem build ol-target-blank.gemspec \ + && gem install ol-target-blank-0.0.1.gem \ + && popd + +# Serve the site +ENTRYPOINT ["bash", "./scripts/jekyll_serve_dev.sh"] + +# Make port 4000 available to the world outside this container +EXPOSE 4000 + + diff --git a/pom.xml b/pom.xml index fc0457503f..87454d4690 100644 --- a/pom.xml +++ b/pom.xml @@ -29,13 +29,22 @@ pom provided - + - junit - junit - 4.5 + org.junit.jupiter + junit-jupiter + 5.6.0 test + + + org.microshed + microshed-testing-liberty + 0.9 + test + + + org.apache.cxf cxf-rt-rs-mp-client @@ -49,6 +58,7 @@ test + org.eclipse yasson @@ -56,7 +66,27 @@ test - + + + org.slf4j + slf4j-log4j12 + 1.7.26 + test + + + + + org.testcontainers + mockserver + 1.14.1 + test + + + org.mock-server + mockserver-client-java + 5.5.4 + test + @@ -68,18 +98,20 @@ false openliberty - - - - target/jekyll-webapp - - io.openliberty.tools liberty-maven-plugin - 3.2 + 3.2.1 + + + org.apache.maven.plugins + maven-failsafe-plugin + 3.0.0-M3 + + false + @@ -94,6 +126,18 @@ + + org.apache.maven.plugins + maven-failsafe-plugin + + + + integration-test + verify + + + + diff --git a/src/main/java/io/openliberty/website/BuildsManager.java b/src/main/java/io/openliberty/website/BuildsManager.java index 74bffbd7c3..b564c31cad 100644 --- a/src/main/java/io/openliberty/website/BuildsManager.java +++ b/src/main/java/io/openliberty/website/BuildsManager.java @@ -50,11 +50,11 @@ public BuildData getData() { } public Map> getBuilds() { - return dheBuilds.getBuildData().builds; + return dheBuilds.getBuildData().getBuilds(); } public LatestReleases getLatestReleases() { - return dheBuilds.getBuildData().latestReleases; + return dheBuilds.getBuildData().getLatestReleases(); } public LastUpdate getStatus() { diff --git a/src/main/java/io/openliberty/website/LatestVersion.java b/src/main/java/io/openliberty/website/LatestVersion.java index 9b61ce2b35..914cb246b4 100644 --- a/src/main/java/io/openliberty/website/LatestVersion.java +++ b/src/main/java/io/openliberty/website/LatestVersion.java @@ -11,13 +11,17 @@ package io.openliberty.website; import java.io.IOException; +import java.util.concurrent.atomic.AtomicReference; + +import javax.enterprise.event.Observes; import javax.inject.Inject; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import io.openliberty.website.data.LatestReleases; +import io.openliberty.website.data.BuildInfo; +import io.openliberty.website.events.RuntimeRelease; /** * The Open Liberty landing page makes a request to a latestVersion.js file in order @@ -33,35 +37,38 @@ public class LatestVersion extends HttpServlet { @Inject private BuildsManager manager; - private String response; - private String version = "0.0.0.0"; private String template = "var latestReleasedVersion = {\r\n" + " version: '0.0.0.0',\r\n" + " productName : 'Open Liberty',\r\n" + " availableFrom : 'https://openliberty.io/downloads?welcome'\r\n" + "};"; + private static AtomicReference response = new AtomicReference<>(); + public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { // send the response. resp.setContentType("application/javascript"); - resp.getWriter().println(response); + resp.getWriter().println(response.get()); } /** * This method gets the latest release and updates the template replacing the Liberty * version with the most recent version. * - * Note this was written assuming that doing it in init would be more efficient, however - * either each request results in a new servlet instance making this redundant, or there - * is reuse at which point the data will be stale when the whole point of this is to be - * super current. This note is here because this needs looking at again. */ public void init() { - LatestReleases releases = manager.getLatestReleases(); - String v = releases.runtime.version; - if (!v.equals(version)) { - response = template.replaceAll("0\\.0\\.0\\.0", v); - version = v; - } + releaseUpdate(manager.getLatestReleases().runtime); + } + + /** + * This method will update the response value when it is notified of a change + * to the runtime release. + * + * @param releaseInfo the build info of the supplied release build + */ + public void releaseUpdate(@Observes @RuntimeRelease BuildInfo releaseInfo) { + String newValue = template.replaceAll("0\\.0\\.0\\.0", releaseInfo.version); + + response.set(newValue); } -} +} \ No newline at end of file diff --git a/src/main/java/io/openliberty/website/OpenLibertyEndpoint.java b/src/main/java/io/openliberty/website/OpenLibertyEndpoint.java index b82667b203..da7ba8da77 100644 --- a/src/main/java/io/openliberty/website/OpenLibertyEndpoint.java +++ b/src/main/java/io/openliberty/website/OpenLibertyEndpoint.java @@ -26,8 +26,8 @@ * This is the main JAX-RS entry point for the Open Liberty website REST API. * The API is defined in the source repo website-api.yml. */ -@ApplicationPath("api") -@Path("/") +@ApplicationPath("/") +@Path("/api") @RequestScoped public class OpenLibertyEndpoint extends Application { diff --git a/src/main/java/io/openliberty/website/data/BuildData.java b/src/main/java/io/openliberty/website/data/BuildData.java index a527ded1c1..4ebb09e28c 100644 --- a/src/main/java/io/openliberty/website/data/BuildData.java +++ b/src/main/java/io/openliberty/website/data/BuildData.java @@ -11,34 +11,45 @@ package io.openliberty.website.data; import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; import java.util.Set; import java.util.TreeSet; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.event.Event; +import javax.inject.Inject; import javax.json.bind.annotation.JsonbProperty; import javax.json.bind.annotation.JsonbTransient; import io.openliberty.website.Constants; +import io.openliberty.website.events.RuntimeRelease; /** * This JSON-B object is the most important one since it is used to provide * the list of all builds to the openliberty.io website. */ +@ApplicationScoped public class BuildData { @JsonbProperty(Constants.LATEST_RELEASES) - public LatestReleases latestReleases = new LatestReleases(); + private LatestReleases latestReleases = new LatestReleases(); @JsonbProperty(Constants.BUILDS) - public ConcurrentMap> builds = new ConcurrentHashMap<>(); + private Map> builds = new HashMap<>(); // These two fields should not be in the JSON-B payload /** The object tracking the last update start and success */ - @JsonbTransient private LastUpdate lastUpdate; /** Tracking how many builds are pending vs completed so we can successfully mark the update as complete */ - @JsonbTransient private AtomicInteger pendingBuilds = new AtomicInteger(); + @Inject + @RuntimeRelease + private Event event; + + + public BuildData() { + this(new LastUpdate()); + } /** * The constructor for this initializes the builds map with a sorted set @@ -64,6 +75,29 @@ public int compare(BuildInfo o1, BuildInfo o2) { } } + @JsonbTransient + public LastUpdate getLastUpdate() { + return lastUpdate; + } + + @JsonbProperty(Constants.LATEST_RELEASES) + public LatestReleases getLatestReleases() { + return latestReleases; + } + + public void setLatestReleases(LatestReleases latest) { + this.latestReleases = latest; + } + + public void setBuilds(Map> builds) { + this.builds = builds; + } + + @JsonbProperty(Constants.BUILDS) + public Map> getBuilds() { + return builds; + } + /** * This method is used to add a new build to the build data. This * method does two things. First it adds it to the map in the right place, @@ -92,6 +126,10 @@ public synchronized void supply(BuildType type, BuildInfo bi) { if (latestReleases.runtime == null || latestReleases.runtime.dateTime.compareTo(bi.dateTime) <= 0) { latestReleases.runtime = bi; + // Notify the build to any CDI event listeners. + if (type.isLatestBuildNotifiable() && event != null) { + event.fire(bi); + } } } else if (type == BuildType.tools_releases) { if (latestReleases.tools == null || diff --git a/src/main/java/io/openliberty/website/data/BuildType.java b/src/main/java/io/openliberty/website/data/BuildType.java index d79eeccb58..3de4cbbbc1 100644 --- a/src/main/java/io/openliberty/website/data/BuildType.java +++ b/src/main/java/io/openliberty/website/data/BuildType.java @@ -18,17 +18,19 @@ * we just flatten them. */ public enum BuildType { - runtime_releases(Constants.DHE_RUNTIME_PATH_SEGMENT, Constants.DHE_RELEASE_PATH_SEGMENT), - runtime_nightly_builds(Constants.DHE_RUNTIME_PATH_SEGMENT, Constants.DHE_NIGHTLY_PATH_SEGMENT), - tools_releases(Constants.DHE_TOOLS_PATH_SEGMENT, Constants.DHE_RELEASE_PATH_SEGMENT), - tools_nightly_builds(Constants.DHE_TOOLS_PATH_SEGMENT, Constants.DHE_NIGHTLY_PATH_SEGMENT); + runtime_releases(Constants.DHE_RUNTIME_PATH_SEGMENT, Constants.DHE_RELEASE_PATH_SEGMENT, true), + runtime_nightly_builds(Constants.DHE_RUNTIME_PATH_SEGMENT, Constants.DHE_NIGHTLY_PATH_SEGMENT, false), + tools_releases(Constants.DHE_TOOLS_PATH_SEGMENT, Constants.DHE_RELEASE_PATH_SEGMENT, false), + tools_nightly_builds(Constants.DHE_TOOLS_PATH_SEGMENT, Constants.DHE_NIGHTLY_PATH_SEGMENT, false); private String type; private String stability; + private boolean notifyOfLatest = false; - BuildType(String type, String stability) { + BuildType(String type, String stability, boolean notify) { this.type = type; this.stability = stability; + this.notifyOfLatest = notify; } /** @@ -45,6 +47,13 @@ public String getStability() { return stability; } + /** + * @return Whether this type of build should be notified as a CDI event if it is latest + */ + public boolean isLatestBuildNotifiable() { + return notifyOfLatest; + } + /** * @return the uri segment under the build repository for this type of build. */ diff --git a/src/main/java/io/openliberty/website/dheclient/DHEBuildParser.java b/src/main/java/io/openliberty/website/dheclient/DHEBuildParser.java index 7213a13b20..2918e58c6d 100644 --- a/src/main/java/io/openliberty/website/dheclient/DHEBuildParser.java +++ b/src/main/java/io/openliberty/website/dheclient/DHEBuildParser.java @@ -10,16 +10,24 @@ *******************************************************************************/ package io.openliberty.website.dheclient; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; +import javax.ws.rs.ProcessingException; +import javax.ws.rs.WebApplicationException; + +import org.eclipse.microprofile.config.inject.ConfigProperty; import io.openliberty.website.Constants; import io.openliberty.website.data.BuildData; @@ -46,9 +54,17 @@ public class DHEBuildParser { @Inject private ScheduledExecutorService exec; - private final LastUpdate lastUpdate = new LastUpdate(); + @Inject + @ConfigProperty(defaultValue = "1", name = "build.sync.period") + private int delay = 1; + @Inject + @ConfigProperty(defaultValue = "HOURS", name = "build.sync.period.unit") + private TimeUnit delayTime = TimeUnit.HOURS; + + @Inject + private volatile BuildData buildData; - private volatile BuildData buildData = new BuildData(lastUpdate); + private List> futures = new ArrayList<>(); /** Defined default constructor */ public DHEBuildParser() { @@ -57,11 +73,13 @@ public DHEBuildParser() { /** Allow for unittest injection */ public DHEBuildParser(BuildStore store) { this.store = store; + this.buildData = new BuildData(); exec = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors()); init(); } public LastUpdate getLastUpdate() { + LastUpdate lastUpdate = buildData.getLastUpdate(); if (logger.isLoggable(Level.FINER)) { logger.log(Level.FINE, "getLastUpdate()", lastUpdate); } @@ -84,31 +102,35 @@ public BuildData getBuildData() { * @param type the type of build to initalize */ private void initBuilds(BuildType type) { - // Do a sync get to load all versions - BuildListInfo buildList = store.getBuildListInfo(type); - - // If something goes wrong this could be null, or an empty list so cope gracefully - if (buildList != null && !buildList.versions.isEmpty()) { - // Sort by reverse natural order, which means the most recently published build - // will be first - Collections.sort(buildList.versions, Comparator.reverseOrder()); - - // notify the number of builds that are about to be fetched. - buildData.pending(buildList.versions.size()); - - // remove the first one and fetch it syncronously. - String mostRecent = buildList.versions.remove(0); - BuildInfo info = store.getBuildInfo(type, mostRecent); - - // add the build into the build data store. - add(type, mostRecent, info); - - // Submit an async thread to go fetch all the other builds. - exec.submit(new RetrieveBuildList(type) { - public void run() { - processBuildList(buildList.versions); - } - }); + try { + // Do a sync get to load all versions + BuildListInfo buildList = store.getBuildListInfo(type); + + // If something goes wrong this could be null, or an empty list so cope gracefully + if (buildList != null && !buildList.versions.isEmpty()) { + // Sort by reverse natural order, which means the most recently published build + // will be first + Collections.sort(buildList.versions, Comparator.reverseOrder()); + + // notify the number of builds that are about to be fetched. + buildData.pending(buildList.versions.size()); + + // remove the first one and fetch it syncronously. + String mostRecent = buildList.versions.remove(0); + BuildInfo info = store.getBuildInfo(type, mostRecent); + + // add the build into the build data store. + add(type, mostRecent, info); + + // Submit an async thread to go fetch all the other builds. + exec.submit(new RetrieveBuildList(type) { + public void run() { + processBuildList(buildList.versions); + } + }); + } + } catch (ProcessingException | WebApplicationException e) { + System.err.println("Failure accessing build: " + type + " error was: " + e.getMessage()); } } @@ -150,12 +172,21 @@ public void init() { initBuilds(BuildType.runtime_releases); initBuilds(BuildType.tools_releases); + System.out.println("Setting up build sync to run every " + delay + " " + delayTime.toString().toLowerCase()); + // We kicked off the release already so we don't need to resync for an hour - exec.scheduleWithFixedDelay(new RetrieveBuildList(BuildType.runtime_releases), 1, 1, TimeUnit.HOURS); - exec.scheduleWithFixedDelay(new RetrieveBuildList(BuildType.tools_releases), 1, 1, TimeUnit.HOURS); + futures.add(exec.scheduleWithFixedDelay(new RetrieveBuildList(BuildType.runtime_releases), delay, delay, delayTime)); + futures.add(exec.scheduleWithFixedDelay(new RetrieveBuildList(BuildType.tools_releases), delay, delay, delayTime)); // We haven't read any data about nightly builds so we need to run this now - exec.scheduleWithFixedDelay(new RetrieveBuildList(BuildType.runtime_nightly_builds), 0, 1, TimeUnit.HOURS); - exec.scheduleWithFixedDelay(new RetrieveBuildList(BuildType.tools_nightly_builds), 0, 1, TimeUnit.HOURS); + futures.add(exec.scheduleWithFixedDelay(new RetrieveBuildList(BuildType.runtime_nightly_builds), 0, delay, delayTime)); + futures.add(exec.scheduleWithFixedDelay(new RetrieveBuildList(BuildType.tools_nightly_builds), 0, delay, delayTime)); + } + + @PreDestroy + public void destroy() { + for (ScheduledFuture future : futures) { + future.cancel(false); + } } /** @@ -170,22 +201,26 @@ class RetrieveBuildList implements Runnable { @Override public void run() { - // find out which builds we need - BuildListInfo listInfo = store.getBuildListInfo(type); - - // If we don't get any builds back just skip. - if (listInfo != null && !listInfo.versions.isEmpty()) { - // Sort by reverse order so we fetch newer builds first. This means that - // we will load builds we don't know about before refrehsing builds we - // already know about. Updating build data doesn't happen often, but it - // does happen. - Collections.sort(listInfo.versions, Comparator.reverseOrder()); - - // Notify that builds are pending - buildData.pending(listInfo.versions.size()); - - // process the build list. - processBuildList(listInfo.versions); + try { + // find out which builds we need + BuildListInfo listInfo = store.getBuildListInfo(type); + + // If we don't get any builds back just skip. + if (listInfo != null && !listInfo.versions.isEmpty()) { + // Sort by reverse order so we fetch newer builds first. This means that + // we will load builds we don't know about before refrehsing builds we + // already know about. Updating build data doesn't happen often, but it + // does happen. + Collections.sort(listInfo.versions, Comparator.reverseOrder()); + + // Notify that builds are pending + buildData.pending(listInfo.versions.size()); + + // process the build list. + processBuildList(listInfo.versions); + } + } catch (ProcessingException | WebApplicationException e) { + System.err.println("Failure accessing builds: " + type + " error was: " + e.getMessage()); } } @@ -198,9 +233,13 @@ public void run() { */ public void processBuildList(Collection versions) { for (String version : versions) { - BuildInfo info = store.getBuildInfo(type, version); + try { + BuildInfo info = store.getBuildInfo(type, version); - add(type, version, info); + add(type, version, info); + } catch (ProcessingException | WebApplicationException e) { + System.err.println("Failure accessing build: " + type + " at " + version + " error was: " + e.getMessage()); + } } } } diff --git a/src/main/java/io/openliberty/website/events/RuntimeRelease.java b/src/main/java/io/openliberty/website/events/RuntimeRelease.java new file mode 100644 index 0000000000..970b199b34 --- /dev/null +++ b/src/main/java/io/openliberty/website/events/RuntimeRelease.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2020 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package io.openliberty.website.events; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.inject.Qualifier; + +@Qualifier +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.PARAMETER}) +public @interface RuntimeRelease { + +} \ No newline at end of file diff --git a/src/main/wlp/server.xml b/src/main/wlp/server.xml index 00d3befdac..3dcfca4aec 100644 --- a/src/main/wlp/server.xml +++ b/src/main/wlp/server.xml @@ -16,6 +16,7 @@ Contributors: concurrent-1.0 cdi-2.0 mpRestClient-1.3 + mpConfig-1.4 transportSecurity-1.0 + target/jekyll-webapp + + From e7084cc4324cf97199ea6cf23f94f402efe33060 Mon Sep 17 00:00:00 2001 From: Alasdair Nottingham Date: Thu, 7 May 2020 17:00:25 -0400 Subject: [PATCH 3/3] Fix the JAX-RS endpoint so it only intercepts api requests --- src/main/java/io/openliberty/website/OpenLibertyEndpoint.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/openliberty/website/OpenLibertyEndpoint.java b/src/main/java/io/openliberty/website/OpenLibertyEndpoint.java index da7ba8da77..9d4018a487 100644 --- a/src/main/java/io/openliberty/website/OpenLibertyEndpoint.java +++ b/src/main/java/io/openliberty/website/OpenLibertyEndpoint.java @@ -26,8 +26,8 @@ * This is the main JAX-RS entry point for the Open Liberty website REST API. * The API is defined in the source repo website-api.yml. */ -@ApplicationPath("/") -@Path("/api") +@ApplicationPath("/api") +@Path("/") @RequestScoped public class OpenLibertyEndpoint extends Application {