blob: 1870a5b38a8da2e39a435ee22b008700e2d1fd58 [file] [log] [blame]
/*
* $Id$
*
* 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.struts2.osgi.admin.actions;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
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.
*
* 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 implements BundleContextAware {
private String command;
private String output;
private BundleContext bundleContext;
@Override
public String execute() {
// get service
ByteArrayOutputStream outByteStream = new ByteArrayOutputStream();
ByteArrayOutputStream errByteStream = new ByteArrayOutputStream();
PrintStream outStream = new PrintStream(outByteStream);
PrintStream errStream = new PrintStream(errByteStream);
String outString = null;
String errString = null;
try {
executeCommand(command, outStream, errStream);
outString = outByteStream.toString().trim();
errString = errByteStream.toString().trim();
} catch (Exception e) {
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();
}
output = errString != null && errString.length() > 0 ? errString : outString;
return Action.SUCCESS;
}
public String getCommand() {
return command;
}
public void setCommand(String command) {
this.command = command;
}
public String getOutput() {
return output;
}
public void executeCommand(String commandLine, PrintStream out, PrintStream err) throws Exception {
ShellService shellService = getShellService(out);
if (shellService != null) {
out.println("Attempting to execute command: " + commandLine);
shellService.executeCommand(commandLine, out, err);
}
else {
err.println("Apache Felix Shell service is not installed");
}
}
private ShellService getShellService(PrintStream out) {
//bundle can be de-activated, so keeping a reference aorund is not a good idea
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;
}
}