diff --git a/bundles/admin/pom.xml b/bundles/admin/pom.xml
index 206625c17..e285ebde0 100644
--- a/bundles/admin/pom.xml
+++ b/bundles/admin/pom.xml
@@ -48,7 +48,7 @@
META-INF
true
- *,com.opensymphony.xwork2
+ *
org.apache.struts2.osgi.admin*
*;create-asynchronously:=false
diff --git a/bundles/admin/src/main/java/org/apache/struts2/osgi/admin/actions/BundlesAction.java b/bundles/admin/src/main/java/org/apache/struts2/osgi/admin/actions/BundlesAction.java
index cf6edb07f..26b703002 100644
--- a/bundles/admin/src/main/java/org/apache/struts2/osgi/admin/actions/BundlesAction.java
+++ b/bundles/admin/src/main/java/org/apache/struts2/osgi/admin/actions/BundlesAction.java
@@ -60,6 +60,9 @@ public class BundlesAction extends ActionSupport implements ServletContextAware
}
public String start() throws BundleException {
+ clearErrorsAndMessages();
+ addActionMessage("Start - OSGi Host: " + osgiHost + ", ID: " + id);
+
Bundle bundle = osgiHost.getBundles().get(id);
try {
bundle.start();
@@ -69,29 +72,35 @@ public class BundlesAction extends ActionSupport implements ServletContextAware
//there no easy way/elegant way to know if the bundle was processed already
Thread.sleep(1000);
} catch (Exception e) {
- addActionError(e.toString());
+ addActionError("Exception: " + e.toString() + " (" + e.getMessage() + ")");
}
return view();
}
public String stop() throws BundleException {
+ clearErrorsAndMessages();
+ addActionMessage("Stop - OSGi Host: " + osgiHost + ", ID: " + id);
+
Bundle bundle = osgiHost.getBundles().get(id);
try {
bundle.stop();
} catch (Exception e) {
- addActionError(e.toString());
+ addActionError("Exception: " + e.toString() + " (" + e.getMessage() + ")");
}
return view();
}
public String update() throws BundleException {
+ clearErrorsAndMessages();
+ addActionMessage("Update - OSGi Host: " + osgiHost + ", ID: " + id);
+
Bundle bundle = osgiHost.getBundles().get(id);
try {
bundle.update();
} catch (Exception e) {
- addActionError(e.toString());
+ addActionError("Exception: " + e.toString() + " (" + e.getMessage() + ")");
}
return view();
@@ -114,14 +123,14 @@ public class BundlesAction extends ActionSupport implements ServletContextAware
}
public List getPackages() {
- List pkgs = new ArrayList();
+ List pkgs = new ArrayList<>();
Bundle bundle = getBundle();
if (bundle.getState() == Bundle.ACTIVE) {
- for (String name : bundleAccessor.getPackagesByBundle(bundle)) {
- PackageConfig packageConfig = configuration.getPackageConfig(name);
- if (packageConfig != null)
- pkgs.add(packageConfig);
- }
+ bundleAccessor.getPackagesByBundle(bundle).stream().map(
+ name -> configuration.getPackageConfig(name)).filter(
+ packageConfig -> (packageConfig != null)).forEachOrdered(packageConfig -> {
+ pkgs.add(packageConfig);
+ });
}
return pkgs;
}
@@ -132,16 +141,14 @@ public class BundlesAction extends ActionSupport implements ServletContextAware
public Collection getBundles() {
List bundles = new ArrayList(osgiHost.getBundles().values());
- Collections.sort(bundles, new Comparator() {
- public int compare(Bundle bundle1, Bundle bundle2) {
- boolean bundle1StrutsEnabled = isStrutsEnabled(bundle1);
- boolean bundle2StrutsEnabled = isStrutsEnabled(bundle2);
+ Collections.sort(bundles, (Bundle bundle1, Bundle bundle2) -> {
+ boolean bundle1StrutsEnabled = isStrutsEnabled(bundle1);
+ boolean bundle2StrutsEnabled = isStrutsEnabled(bundle2);
- if ((bundle1StrutsEnabled && bundle2StrutsEnabled) || (!bundle1StrutsEnabled && !bundle2StrutsEnabled))
- return bundle1.getSymbolicName().compareTo(bundle2.getSymbolicName());
- else {
- return bundle1StrutsEnabled ? -1 : 1;
- }
+ if ((bundle1StrutsEnabled && bundle2StrutsEnabled) || (!bundle1StrutsEnabled && !bundle2StrutsEnabled)) {
+ return bundle1.getSymbolicName().compareTo(bundle2.getSymbolicName());
+ } else {
+ return bundle1StrutsEnabled ? -1 : 1;
}
});
return bundles;
@@ -172,17 +179,21 @@ public class BundlesAction extends ActionSupport implements ServletContextAware
try {
state = bundle.getState();
} catch (Exception e) {
- addActionError("Unable to determine bundle state: " + e.getMessage());
+ addActionError("Unable to determine bundle state. Exception: " + e.toString() + " (" + e.getMessage() + ")");
return false;
}
- if ("start".equals(val)) {
- return state == Bundle.RESOLVED;
- } else if ("stop".equals(val)) {
- return state == Bundle.ACTIVE;
- } else if ("update".equals(val)) {
- return state == Bundle.ACTIVE || state == Bundle.INSTALLED
- || state == Bundle.RESOLVED;
+ if (val != null) {
+ switch (val) {
+ case "start":
+ return state == Bundle.RESOLVED;
+ case "stop":
+ return state == Bundle.ACTIVE;
+ case "update":
+ return state == Bundle.ACTIVE || state == Bundle.INSTALLED || state == Bundle.RESOLVED;
+ default:
+ break;
+ }
}
throw new IllegalArgumentException("Invalid state");
}
@@ -197,6 +208,7 @@ public class BundlesAction extends ActionSupport implements ServletContextAware
this.bundleAccessor = bundleAccessor;
}
+ @Override
public void withServletContext(ServletContext servletContext) {
osgiHost = (OsgiHost) servletContext.getAttribute(StrutsOsgiListener.OSGI_HOST);
}
diff --git a/bundles/admin/src/main/java/org/apache/struts2/osgi/admin/actions/ShellAction.java b/bundles/admin/src/main/java/org/apache/struts2/osgi/admin/actions/ShellAction.java
index eba64bbd9..1870a5b38 100644
--- a/bundles/admin/src/main/java/org/apache/struts2/osgi/admin/actions/ShellAction.java
+++ b/bundles/admin/src/main/java/org/apache/struts2/osgi/admin/actions/ShellAction.java
@@ -24,20 +24,29 @@ package org.apache.struts2.osgi.admin.actions;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
-import org.apache.struts2.osgi.DefaultBundleAccessor;
import org.apache.felix.shell.ShellService;
+import org.apache.struts2.osgi.DefaultBundleAccessor;
+import org.apache.struts2.osgi.interceptor.BundleContextAware;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionSupport;
/**
- * This action executes commands on the Felix Shell
+ * This action executes commands on the Felix Shell.
+ *
+ * The action is BundleContextAware so that if the OSGi interceptor is used the BundleContext
+ * can be provided for configurations where the DefaultBundleAccessor is insufficient.
+ *
*/
-public class ShellAction extends ActionSupport {
+public class ShellAction extends ActionSupport implements BundleContextAware {
private String command;
private String output;
+ private BundleContext bundleContext;
+ @Override
public String execute() {
// get service
ByteArrayOutputStream outByteStream = new ByteArrayOutputStream();
@@ -52,7 +61,9 @@ public class ShellAction extends ActionSupport {
outString = outByteStream.toString().trim();
errString = errByteStream.toString().trim();
} catch (Exception e) {
- errString = e.getMessage();
+ outString = outByteStream.toString().trim();
+ errString = "Exception: " + e.toString() + " (" + e.getMessage() + "). Output:" + outString +
+ ". Error: " + errByteStream.toString().trim(); // Full details for troubleshooting.
} finally {
outStream.close();
errStream.close();
@@ -75,17 +86,59 @@ public class ShellAction extends ActionSupport {
}
public void executeCommand(String commandLine, PrintStream out, PrintStream err) throws Exception {
- ShellService shellService = getShellService();
- if (shellService != null)
+ ShellService shellService = getShellService(out);
+ if (shellService != null) {
+ out.println("Attempting to execute command: " + commandLine);
shellService.executeCommand(commandLine, out, err);
- else
+ }
+ else {
err.println("Apache Felix Shell service is not installed");
+ }
}
- private ShellService getShellService() {
+ private ShellService getShellService(PrintStream out) {
//bundle can be de-activated, so keeping a reference aorund is not a good idea
- DefaultBundleAccessor bundleAcessor = DefaultBundleAccessor.getInstance();
- ServiceReference ref = bundleAcessor.getServiceReference(ShellService.class.getName());
- return (ShellService) bundleAcessor.getService(ref);
+ final DefaultBundleAccessor bundleAccessor = DefaultBundleAccessor.getInstance();
+ ServiceReference ref = (bundleAccessor != null ? bundleAccessor.getServiceReference(ShellService.class.getName()) : null);
+ //out.println("DefaultBundleAccessor: " + bundleAcessor + ", ServiceReference [" + ShellService.class.getName() + "]: " + ref); // No logger, for debugging only.
+
+ if (ref == null && this.bundleContext != null) {
+ // Depending on OSGi and Felix bundle configurations, the DefaultBundleAccessor may not be able to locate the ShellService.
+ // In such cases, use the bundleContext (if available) to locate the ShellService in a "brute-force" manner.
+ final Bundle[] bundles = this.bundleContext.getBundles();
+ if (bundles != null && bundles.length > 0) {
+ for (Bundle currentBundle : bundles) {
+ if (currentBundle != null) {
+ //out.println("Bundle [" + index + "], SymbolicName: " + currentBundle.getSymbolicName() + ", Location: " + currentBundle.getLocation() + ", BundleID: " + currentBundle.getBundleId()); // No logger, for debugging only.
+ if (currentBundle.getSymbolicName().startsWith("org.apache.felix.shell")) {
+ BundleContext currentBundleContext = currentBundle.getBundleContext();
+ Object directShellServiceByClass = (currentBundleContext != null ? currentBundleContext.getServiceReference(org.apache.felix.shell.ShellService.class) : null);
+ Object directShellServiceByName = (currentBundleContext != null ? currentBundleContext.getServiceReference("org.apache.felix.shell.ShellService") : null);
+ //out.println(" ShellService reference (via bundle's context) by class: " + directShellServiceByClass); // No logger, for debugging only.
+ //out.println(" ShellService reference (via bundle's context) by name: " + directShellServiceByName); // No logger, for debugging only.
+ if (ref == null) {
+ ref = (directShellServiceByClass != null ? (ServiceReference) directShellServiceByClass : (ServiceReference) directShellServiceByName);
+ }
+ }
+ } else {
+ //out.println("Bundle [" + index + "] is null"); // No logger, for debugging only.
+ }
+ }
+ } else {
+ //out.println("OSGi Interceptor-provided BundleContext bundle array is null or empty"); // No logger, for debugging only.
+ }
+ }
+
+ if (ref == null) {
+ out.println("ShellService reference cannot be found (null), service lookup will fail.");
+ }
+
+ return (ShellService) (bundleAccessor != null ? bundleAccessor.getService(ref) : null);
+ }
+
+ @Override
+ public void setBundleContext(BundleContext bundleContext) {
+ //System.out.println("ShellAction - setBundleContext called. BundleContext: " + bundleContext); // No logger, for debugging only.
+ this.bundleContext = bundleContext;
}
}
diff --git a/bundles/admin/src/main/resources/JQUERY-LICENSE.txt b/bundles/admin/src/main/resources/JQUERY-LICENSE.txt
index f0f2ba90b..4819e5421 100644
--- a/bundles/admin/src/main/resources/JQUERY-LICENSE.txt
+++ b/bundles/admin/src/main/resources/JQUERY-LICENSE.txt
@@ -1,9 +1,13 @@
-Copyright (c) 2009 Paul Bakaus, http://jqueryui.com/
+Copyright jQuery Foundation and other contributors, https://jquery.org/
This software consists of voluntary contributions made by many
-individuals (AUTHORS.txt, http://jqueryui.com/about) For exact
-contribution history, see the revision history and logs, available
-at http://jquery-ui.googlecode.com/svn/
+individuals. For exact contribution history, see the revision history
+available at https://github.com/jquery/jquery-ui
+
+The following license applies to all parts of this software except as
+documented below:
+
+====
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -23,3 +27,17 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+====
+
+Copyright and related rights for sample code are waived via CC0. Sample
+code is defined as all source code contained within the demos directory.
+
+CC0: http://creativecommons.org/publicdomain/zero/1.0/
+
+====
+
+All files located in the node_modules and external directories are
+externally maintained libraries used by this software which have their
+own licenses; we recommend you read them, as their terms may differ from
+the terms above.
diff --git a/bundles/admin/src/main/resources/NOTICE.txt b/bundles/admin/src/main/resources/NOTICE.txt
index c3a9a79a1..2494732ef 100644
--- a/bundles/admin/src/main/resources/NOTICE.txt
+++ b/bundles/admin/src/main/resources/NOTICE.txt
@@ -2,7 +2,8 @@ Apache Struts
Copyright 2000-2011 The Apache Software Foundation
This product includes software developed by
-The Apache Software Foundation (http://www.apache.org/).
+The Apache Software Foundation (https://www.apache.org/).
The binary distributions includes the following third party software:
-JQuery (http://jquery.com/).
+jQuery (https://jquery.com/).
+jQuery UI (https://jqueryui.com/).
diff --git a/bundles/admin/src/main/resources/osgi/admin/shell.ftl b/bundles/admin/src/main/resources/osgi/admin/shell.ftl
index 3c92ea5f6..aa7d8a9f2 100644
--- a/bundles/admin/src/main/resources/osgi/admin/shell.ftl
+++ b/bundles/admin/src/main/resources/osgi/admin/shell.ftl
@@ -24,11 +24,11 @@
" />
" />
- " />
+ " />
">
- ">
- ">
+ ">
+ ">
+
+<@s.actionerror />
+
+
+<@s.actionmessage />
+