diff options
author | Herbert Eiselt <herbert.eiselt@highstreet-technologies.com> | 2019-01-30 09:45:54 +0100 |
---|---|---|
committer | Herbert Eiselt <herbert.eiselt@highstreet-technologies.com> | 2019-01-30 09:46:13 +0100 |
commit | 8d39a39c646154b3e746564536b890a0200bc37b (patch) | |
tree | 9006737ef3672dc6d7faf9a5d4c9b10313420cc0 /sdnr/wt/helpserver/provider/src/main/java | |
parent | 316dbd689e4dea400b9d8fc6d91e1b13191fa868 (diff) |
Add sdnr wt helpserver
Add complete sdnr wireless transport app helpserver
Change-Id: I01ba5a2a4b6dbd8fbfd91bbb5a1ae5db7b181f2d
Issue-ID: SDNC-577
Signed-off-by: Herbert Eiselt <herbert.eiselt@highstreet-technologies.com>
Diffstat (limited to 'sdnr/wt/helpserver/provider/src/main/java')
4 files changed, 648 insertions, 0 deletions
diff --git a/sdnr/wt/helpserver/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/helpserver/HelpServlet.java b/sdnr/wt/helpserver/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/helpserver/HelpServlet.java new file mode 100644 index 000000000..76ac17bb6 --- /dev/null +++ b/sdnr/wt/helpserver/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/helpserver/HelpServlet.java @@ -0,0 +1,291 @@ +/******************************************************************************* + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * ============LICENSE_END========================================================================== + ******************************************************************************/ +package org.onap.ccsdk.features.sdnr.wt.helpserver; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLDecoder; +import java.nio.file.Path; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.onap.ccsdk.features.sdnr.wt.helpserver.data.HelpInfrastructureObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HelpServlet extends HttpServlet implements AutoCloseable { + + private static Logger LOG = LoggerFactory.getLogger(HelpServlet.class); + private static final long serialVersionUID = -4285072760648493461L; + + private static final boolean USE_FILESYSTEM = true; + private static final boolean USE_RESSOURCES = !USE_FILESYSTEM; + private static final String BASEURI = "/help"; + + private static final boolean REDIRECT_LINKS = true; + + private final Path basePath; + + public HelpServlet() { + LOG.info("Starting HelpServlet instance {}", this.hashCode()); + HelpInfrastructureObject.createFilesFromResources(); + this.basePath = HelpInfrastructureObject.getHelpDirectoryBase(); + } + + @Override + protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + resp.addHeader("Access-Control-Allow-Origin", "*"); + resp.addHeader("Access-Control-Allow-Methods", "OPTIONS, HEAD, GET, POST, PUT, DELETE"); + resp.addHeader("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, Content-Length"); + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse) Handle Get Request: if query=?meta=send json + * infrastructure for README.md else if file exist send file + */ + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String query = req.getQueryString(); + resp.addHeader("Access-Control-Allow-Origin", "*"); + resp.addHeader("Access-Control-Allow-Methods", "OPTIONS, HEAD, GET, POST, PUT, DELETE"); + resp.addHeader("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, Content-Length"); + if (query != null && query.contains("meta")) { + /* + * LOG.debug("received post with uri="+req.getRequestURI()); String + * uri=req.getRequestURI().substring(BASEURI.length()); if(uri.startsWith("/")) + * uri=uri.substring(1); + */ + File f = new File(HelpInfrastructureObject.KARAFHELPDIRECTORY, "meta.json"); + if (f.exists()) { + LOG.debug("found local meta file"); + try (BufferedReader rd = new BufferedReader(new FileReader(f));) { + String line = rd.readLine(); + while (line != null) { + resp.getOutputStream().println(line); + line = rd.readLine(); + } + rd.close(); + } catch (IOException e) { + LOG.debug("Can not read meta file", e); + } + } else { + LOG.debug("start walking from path=" + basePath.toAbsolutePath().toString()); + HelpInfrastructureObject o = null; + if (USE_FILESYSTEM) { + try { + o = new HelpInfrastructureObject(this.basePath); + } catch (URISyntaxException e) { + LOG.debug("Can not relsolve URI. ", e); + } + } else if (USE_RESSOURCES) { + // o=new HelpInfrastructureObject() + } + resp.getOutputStream().println(o != null ? o.toString() : ""); + } + resp.setHeader("Content-Type", "application/json"); + } else { + LOG.debug("received get with uri=" + req.getRequestURI()); + String uri = URLDecoder.decode(req.getRequestURI().substring(BASEURI.length()), "UTF-8"); + if (uri.startsWith("/")) { + uri = uri.substring(1); + } + Path p = basePath.resolve(uri); + if (USE_FILESYSTEM) { + File f = p.toFile(); + if (f.isFile() && f.exists()) { + LOG.debug("found file for request"); + if (this.isTextFile(f)) { + resp.setHeader("Content-Type", "application/text"); + resp.setHeader("charset", "utf-8"); + } else if (this.isImageFile(f)) { + resp.setHeader("Content-Type", "image/*"); + } else if (this.ispdf(f)) { + resp.setHeader("Content-Type", "application/pdf"); + } else { + LOG.debug("file is not allowed to deliver"); + resp.setStatus(404); + return; + } + LOG.debug("delivering file"); + OutputStream out = resp.getOutputStream(); + String version = null; + if (REDIRECT_LINKS) { + version = getVersionFromRequestedUri(uri); + } + if (this.isTextFile(f) && REDIRECT_LINKS && version != null) { + final String regex = + "(!?\\[[^\\]]*?\\])\\(((?:(?!http|www\\.|\\#|\\.com|\\.net|\\.info|\\.org|\\.svg|\\.png|\\.jpg|\\.gif|\\.jpeg|\\.pdf).)*?)\\)"; + final Pattern pattern = Pattern.compile(regex); + Matcher matcher; + String line; + try (BufferedReader br = new BufferedReader(new FileReader(f))) { + line = br.readLine(); + while (line != null) { + // check line for internal link + matcher = pattern.matcher(line); + if (matcher.find()) { + // extend link with specific version + line = line.replace(matcher.group(2), + "../" + matcher.group(2) + version + "/README.md"); + } + out.write((line + "\n").getBytes()); + line = br.readLine(); + + } + out.flush(); + out.close(); + br.close(); + } + + } else { + try (FileInputStream in = new FileInputStream(f)) { + + byte[] buffer = new byte[1024]; + int len; + while ((len = in.read(buffer)) != -1) { + out.write(buffer, 0, len); + } + in.close(); + out.flush(); + out.close(); + } + } + } else { + LOG.debug("found not file for request"); + resp.setStatus(404); + } + } else if (USE_RESSOURCES) { + URL resurl = this.getClass().getResource(p.toString()); + if (resurl != null)// resource file found + { + if (this.isTextFile(resurl)) { + resp.setHeader("Content-Type", "application/text"); + resp.setHeader("charset", "utf-8"); + } else if (this.isImageFile(resurl)) { + resp.setHeader("Content-Type", "image/*"); + } else if (this.ispdf(resurl)) { + resp.setHeader("Content-Type", "application/pdf"); + } else { + resp.setStatus(404); + return; + } + try (InputStream in = this.getClass().getResourceAsStream(p.toString())) { + OutputStream out = resp.getOutputStream(); + byte[] buffer = new byte[1024]; + int len; + while ((len = in.read(buffer)) != -1) { + out.write(buffer, 0, len); + } + in.close(); + out.flush(); + out.close(); + } + + } else // resource file not found + { + resp.setStatus(404); + } + } + } + } + + /* + * + * uri = "help/folder1/folder2/version/README.md" + */ + private static String getVersionFromRequestedUri(String uri) { + if (uri == null) { + return null; + } + int lastidx = uri.lastIndexOf("/"); + if (lastidx < 0) { + return null; + } + int slastidx = uri.lastIndexOf("/", lastidx - 1); + if (slastidx < 0) { + return null; + } + return uri.substring(slastidx + 1, lastidx); + + } + + private boolean isTextFile(URL url) { + return url != null ? this.isTextFile(url.toString()) : false; + } + + private boolean ispdf(URL url) { + return url != null ? this.ispdf(url.toString()) : false; + } + + private boolean isImageFile(URL url) { + return url != null ? this.isImageFile(url.toString()) : false; + } + + private boolean ispdf(File f) { + return f != null ? this.ispdf(f.getName()) : false; + } + + private boolean ispdf(String name) { + return name != null ? name.toLowerCase().endsWith("pdf") : false; + } + + private boolean isImageFile(File f) { + return f != null ? this.isImageFile(f.getName()) : false; + } + + private boolean isImageFile(String name) { + + return name != null + ? name.toLowerCase().endsWith("png") || name.toLowerCase().endsWith("jpg") + || name.toLowerCase().endsWith("jpeg") || name.toLowerCase().endsWith("svg") + || name.toLowerCase().endsWith("eps") + : false; + } + + private boolean isTextFile(File f) { + return f != null ? this.isTextFile(f.getName()) : false; + + } + + private boolean isTextFile(String name) { + return name != null + ? name.toLowerCase().endsWith("md") || name.toLowerCase().endsWith("txt") + || name.toLowerCase().endsWith("html") || name.toLowerCase().endsWith("htm") + || name.toLowerCase().endsWith("js") || name.toLowerCase().endsWith("css") + : false; + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {} + + @Override + public void close() throws Exception {} +} diff --git a/sdnr/wt/helpserver/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/helpserver/data/Environment.java b/sdnr/wt/helpserver/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/helpserver/data/Environment.java new file mode 100644 index 000000000..bbbccdb10 --- /dev/null +++ b/sdnr/wt/helpserver/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/helpserver/data/Environment.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * ============LICENSE_END========================================================================== + ******************************************************************************/ +package org.onap.ccsdk.features.sdnr.wt.helpserver.data; + +import java.net.Inet4Address; +import java.net.UnknownHostException; +import java.util.Map; + +public class Environment { + + public static String getVar(String v) + { + if(v.equals("$HOSTNAME")) + try { + return Inet4Address.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + + } + Map<String, String> env = System.getenv(); + for (String envName : env.keySet()) { + if(envName!=null && envName.equals(v)) + return env.get(envName); + } + return null; + } +} diff --git a/sdnr/wt/helpserver/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/helpserver/data/ExtactBundleResource.java b/sdnr/wt/helpserver/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/helpserver/data/ExtactBundleResource.java new file mode 100644 index 000000000..ac99849dc --- /dev/null +++ b/sdnr/wt/helpserver/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/helpserver/data/ExtactBundleResource.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * ============LICENSE_END========================================================================== + ******************************************************************************/ +package org.onap.ccsdk.features.sdnr.wt.helpserver.data; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Enumeration; + +import org.osgi.framework.Bundle; + +/** + * Extract subtree with resources from Opendaylight/Karaf/OSGi bundle into Karaf directory<br> + * + * Reference: Eclipsezone @see <a href="https://www.eclipsezone.com/eclipse/forums/t101557.html">https://www.eclipszone.com</a> + * <br><br> + * Example for resource and directory path from karaf log. + * write resource: help/FAQ/0.4.0/README.md + * Create directories for: data/cache/com.highstreet.technologies.help/help/FAQ/0.4.0/README.md + * Open the file: data/cache/com.highstreet.technologies.help/help/FAQ/0.4.0/README.md + * Problem: Binary, JPG files => do not use buffer related functions + * + * Hint: Werify with file manager the content of the bundle.jar file to see the location of the resources. + * There is no need to mark them via the classpath. + */ + +public class ExtactBundleResource { + + /** + * Extract resources from Karaf/OSGi bundle into karaf directory structure. + * @param bundle Karaf/OSGi bundle with resources + * @param filePrefix prefix in karaf file system for destination e.g. "data/cache/com.highstreet.technologies." + * @param ressoureRoot root name of ressources, with leading "/". e.g. "/help" + * @throws IOException In case of problems. + */ + public static void copyBundleResoucesRecursively(Bundle bundle, String filePrefix, String ressoureRoot) throws IOException { + copyResourceTreeRecurse(bundle, filePrefix, bundle.getEntryPaths(ressoureRoot)); + } + + /** + * Delete a file or a directory and its children. + * @param file The directory to delete. + * @throws IOException Exception when problem occurs during deleting the directory. + */ + public static void deleteRecursively(File file) throws IOException { + + if (file.isDirectory()) { + for (File childFile : file.listFiles()) { + if (childFile.isDirectory()) { + deleteRecursively(childFile); + } else { + if (!childFile.delete()) { + throw new IOException(); + } + } + } + } + + if (!file.delete()) { + throw new IOException(); + } + } + + // ------------- Private functions + + /** + * Recurse function to steps through the resource element tree + * @param b Bundle index for bundle with resourcs + * @param filePrefix + * @param resource + * @throws IOException + */ + private static void copyResourceTreeRecurse(Bundle b, String filePrefix, Enumeration<String> resource) throws IOException { + while (resource.hasMoreElements()) { + String name = resource.nextElement(); + Enumeration<String> list = b.getEntryPaths(name); + if (list != null) { + copyResourceTreeRecurse(b, filePrefix, list); + } else { + //Read + File targetFile = new File(filePrefix+name); + targetFile.getParentFile().mkdirs(); + + try(InputStream in = b.getEntry(name).openStream(); + OutputStream outStream = new FileOutputStream(targetFile);) { + + int theInt; + while ((theInt = in.read()) >= 0) { + outStream.write(theInt); + } + in.close(); + outStream.flush(); + outStream.close(); + } + } + } + } +} diff --git a/sdnr/wt/helpserver/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/helpserver/data/HelpInfrastructureObject.java b/sdnr/wt/helpserver/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/helpserver/data/HelpInfrastructureObject.java new file mode 100644 index 000000000..11042d13a --- /dev/null +++ b/sdnr/wt/helpserver/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/helpserver/data/HelpInfrastructureObject.java @@ -0,0 +1,201 @@ +/******************************************************************************* + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * ============LICENSE_END========================================================================== + ******************************************************************************/ +package org.onap.ccsdk.features.sdnr.wt.helpserver.data; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import org.json.JSONObject; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HelpInfrastructureObject extends JSONObject { + + private static final Logger LOG = LoggerFactory.getLogger(HelpInfrastructureObject.class); + private static String HELPBASE = "help"; + private static String KARAFBUNDLERESOURCEHELPROOT = "/" + HELPBASE; + private static String KARAFHELPDIRPREFIX = "data/cache/com.highstreet.technologies."; + public static File KARAFHELPDIRECTORY = new File(KARAFHELPDIRPREFIX + HELPBASE); + + public static class VersionObject extends JSONObject { + private static Comparator<VersionObject> comp; + private final String mVersion; + + public String getVersion() { + return this.mVersion; + } + + public VersionObject(String path, String date, String label, String version) { + this.mVersion = version; + this.put("path", path); + this.put("date", date); + this.put("label", label); + } + + public static Comparator<VersionObject> getComparer() { + if (comp == null) { + comp = (o1, o2) -> o1.getVersion().compareTo(o2.getVersion()); + } + return comp; + } + + public VersionObject cloneAsLatest() { + return new VersionObject(this.getString("path"), this.getString("date"), this.getString("label"), "latest"); + } + + public VersionObject cloneAsCurrent() { + return new VersionObject(this.getString("path"), this.getString("date"), this.getString("label"), + "current"); + } + } + public static class NodeObject extends JSONObject { + public NodeObject(Path base, File dir, String label, ArrayList<VersionObject> versions) { + this.put("label", label); + if (versions != null && versions.size() > 0) { + JSONObject o = new JSONObject(); + this.put("versions", o); + for (VersionObject version : versions) { + o.put(version.getVersion(), version); + } + + } + File[] list = dir.listFiles(); + if (list == null) { + return; + } + for (File f : list) { + if (f.isDirectory()) { + ArrayList<VersionObject> versions2 = findReadmeVersionFolders(base, f.toPath(), true); + if (versions2 != null && versions2.size() > 0) { + JSONObject nodes; + if (!this.has("nodes")) { + this.put("nodes", new JSONObject()); + } + nodes = this.getJSONObject("nodes"); + + NodeObject o = new NodeObject(base, f, f.getName(), versions2); + nodes.put(o.getString("label").toLowerCase(), o); + } + } + } + } + + } + + public HelpInfrastructureObject(Path proot) throws URISyntaxException { + File root = proot.toFile(); + File[] list = root.listFiles(); + if (list == null) { + return; + } + for (File f : list) { + if (f.isDirectory()) { + ArrayList<VersionObject> versions = findReadmeVersionFolders(root.toPath(), f.toPath(), true); + if (versions != null && versions.size() > 0) { + NodeObject o = new NodeObject(proot, f, f.getName(), versions); + this.put(o.getString("label").toLowerCase(), o); + } + } + } + + + } + + public static void walk(ArrayList<File> results, String path) { + + File root = new File(path); + File[] list = root.listFiles(); + + if (list == null) { + return; + } + + for (File f : list) { + if (f.isDirectory()) { + walk(results, f.getAbsolutePath()); + // System.out.println( "Dir:" + f.getAbsoluteFile() ); + } else { + // System.out.println( "File:" + f.getAbsoluteFile() ); + if (f.isFile() && f.getName().endsWith(".md")) { + results.add(f); + } + } + } + } + + private static ArrayList<VersionObject> findReadmeVersionFolders(Path base, Path root, boolean appendCurrent) { + ArrayList<VersionObject> list = new ArrayList<>(); + File[] files = root.toFile().listFiles(); + int baselen = base.toFile().getAbsolutePath().length(); + if (files != null) { + for (File f : files) { + if (f.isDirectory() && new File(f.getAbsolutePath() + "/README.md").exists()) { + list.add(new VersionObject(f.getAbsolutePath().substring(baselen + 1) + "/README.md", "", "", + f.getName())); + } + } + } + Collections.sort(list, VersionObject.getComparer()); + Collections.reverse(list); + if (list.size() > 0 && appendCurrent) { + list.add(list.get(0).cloneAsCurrent()); + } + return list; + } + + + public static void createFilesFromResources() { + + if (KARAFHELPDIRECTORY.exists()) { + LOG.info("Delete existing directory"); + try { + ExtactBundleResource.deleteRecursively(KARAFHELPDIRECTORY); + } catch (IOException e1) { + LOG.warn(e1.toString()); + } + } + + LOG.info("Extract"); + try { + Bundle b = FrameworkUtil.getBundle(HelpInfrastructureObject.class); + if (b == null) { + LOG.info("No bundlereference: Use target in filesystem."); + // URL helpRessource = + // JarFileUtils.stringToJarURL("target/helpserver-impl-0.4.0-SNAPSHOT.jar",KARAFBUNDLERESOURCEHELPROOT); + + } else { + LOG.info("Bundle location:{} State:{}", b.getLocation(), b.getState()); + LOG.info("Write files from Resource"); + ExtactBundleResource.copyBundleResoucesRecursively(b, "data/cache/com.highstreet.technologies.", + KARAFBUNDLERESOURCEHELPROOT); + } + } catch (IOException e) { + LOG.warn("No help files available. Exception: " + e.toString()); + } + } + + public static Path getHelpDirectoryBase() { + return KARAFHELPDIRECTORY.toPath(); + } +} |