Index: appserver/osgi-platforms/felix-cli-remote/src/main/java/org/glassfish/osgi/felix/shell/remote/RemoteCommandSession.java
===================================================================
--- appserver/osgi-platforms/felix-cli-remote/src/main/java/org/glassfish/osgi/felix/shell/remote/RemoteCommandSession.java (revision 0)
+++ appserver/osgi-platforms/felix-cli-remote/src/main/java/org/glassfish/osgi/felix/shell/remote/RemoteCommandSession.java (revision 0)
@@ -0,0 +1,140 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
+ * or packager/legal/LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at packager/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+package org.glassfish.osgi.felix.shell.remote;
+
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.lang.reflect.Field;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.UUID;
+import org.apache.felix.service.command.CommandSession;
+
+/**
+ * This delegating class is used to overcome some limitations of the
+ * {@link CommandSession} interface when it comes to session management.
+ *
+ *
+ * Once implementations are mature enough to not assume environmental behavior
+ * this class will become obsolete.
+ *
+ *
+ * @author ancoron
+ */
+public class RemoteCommandSession {
+
+ private final CommandSession delegate;
+ private final String id;
+
+ public RemoteCommandSession(CommandSession delegate)
+ {
+ this.delegate = delegate;
+ this.id = UUID.randomUUID().toString();
+ }
+
+ /**
+ * Get the identifier for this session, which is a UUID of type 4.
+ *
+ * @return
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Attached the specified streams to the delegate of this instance and
+ * returns the modified delegate.
+ *
+ * @param in The "stdin" stream for the session
+ * @param out The "stdout" stream for the session
+ * @param err The "stderr" stream for the session
+ *
+ * @return The modified {@link CommandSession} delegate
+ *
+ * @see #detach()
+ */
+ public CommandSession attach(InputStream in, PrintStream out, PrintStream err) {
+ set(this.delegate, "in", in);
+ set(this.delegate, "out", out);
+ set(this.delegate, "err", err);
+ return this.delegate;
+ }
+
+ /**
+ * Detaches all previously attached streams and hence, ensures that there
+ * are no stale references left.
+ *
+ * @see #attach(java.io.InputStream, java.io.PrintStream, java.io.PrintStream)
+ */
+ public void detach() {
+ set(this.delegate, "in", null);
+ set(this.delegate, "out", null);
+ set(this.delegate, "err", null);
+ }
+
+ private void set(final Object obj, final String field, final Object value) {
+ try {
+ final Field f = obj.getClass().getDeclaredField(field);
+ final boolean accessible = f.isAccessible();
+ if(!accessible) {
+ AccessController.doPrivileged(new PrivilegedAction() {
+
+ @Override
+ public Void run() {
+ f.setAccessible(true);
+ try {
+ f.set(obj, value);
+ } catch(Exception x) {
+ throw new RuntimeException(x);
+ }
+
+ // reset to previous state...
+ f.setAccessible(accessible);
+ return null;
+ }
+ });
+ } else {
+ f.set(obj, value);
+ }
+ } catch(Exception x) {
+ throw new RuntimeException(x);
+ }
+ }
+}
Index: appserver/osgi-platforms/felix-cli-remote/src/main/java/org/glassfish/osgi/felix/shell/remote/FelixShellCommand.java
===================================================================
--- appserver/osgi-platforms/felix-cli-remote/src/main/java/org/glassfish/osgi/felix/shell/remote/FelixShellCommand.java (revision 0)
+++ appserver/osgi-platforms/felix-cli-remote/src/main/java/org/glassfish/osgi/felix/shell/remote/FelixShellCommand.java (revision 0)
@@ -0,0 +1,312 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
+ * or packager/legal/LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at packager/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+package org.glassfish.osgi.felix.shell.remote;
+
+import com.sun.enterprise.admin.remote.ServerRemoteAdminCommand;
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.config.serverbeans.Server;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.inject.Inject;
+import org.apache.felix.service.command.CommandProcessor;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.felix.shell.ShellService;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.I18n;
+import org.glassfish.api.Param;
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.api.admin.CommandException;
+import org.glassfish.api.admin.CommandLock;
+import org.glassfish.api.admin.ParameterMap;
+import org.glassfish.api.admin.RestEndpoint;
+import org.glassfish.api.admin.RestEndpoints;
+import org.glassfish.config.support.CommandTarget;
+import org.glassfish.config.support.TargetType;
+import org.glassfish.hk2.api.PerLookup;
+import org.glassfish.hk2.api.PostConstruct;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.jvnet.hk2.annotations.Service;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleReference;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * A simple AdminCommand that bridges to the Felix Shell Service.
+ *
+ * @author ancoron
+ */
+@Service(name = "felix")
+@CommandLock(CommandLock.LockType.SHARED)
+@I18n("felix")
+@PerLookup
+@TargetType({CommandTarget.CLUSTERED_INSTANCE, CommandTarget.STANDALONE_INSTANCE})
+@RestEndpoints({
+ @RestEndpoint(configBean=Domain.class,
+ opType=RestEndpoint.OpType.POST,
+ path="felix",
+ description="Remote Felix Shell Access")
+})
+public class FelixShellCommand implements AdminCommand, PostConstruct {
+
+ private static final Logger log = Logger.getLogger(FelixShellCommand.class.getPackage().getName());
+
+ private static final Map sessions =
+ new ConcurrentHashMap();
+
+ @Param(name = "command-line", primary = true, optional = true, multiple = true, defaultValue = "help")
+ private Object commandLine;
+
+ @Param(name = "session", optional = true)
+ private String sessionOp;
+
+ @Param(name = "session-id", optional = true)
+ private String sessionId;
+
+ @Param(name = "instance", optional = true)
+ private String instance;
+
+ protected BundleContext ctx;
+
+ @Inject
+ ServiceLocator locator;
+
+ @Inject
+ Domain domain;
+
+ @Override
+ public void execute(AdminCommandContext context) {
+ ActionReport report = context.getActionReport();
+
+ if(instance != null) {
+ Server svr = domain.getServerNamed(instance);
+ if(svr == null) {
+ report.setMessage("No server target found for "
+ + instance);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ return;
+ }
+ String host = svr.getAdminHost();
+ int port = svr.getAdminPort();
+
+ try {
+ ServerRemoteAdminCommand remote =
+ new ServerRemoteAdminCommand(
+ locator,
+ "felix",
+ host,
+ port,
+ false,
+ "admin",
+ "",
+ log);
+
+ ParameterMap params = new ParameterMap();
+
+ if(commandLine == null) {
+ params.set("DEFAULT".toLowerCase(), "asadmin-felix-shell");
+ } else if(commandLine instanceof String) {
+ params.set("DEFAULT".toLowerCase(), (String) commandLine);
+ } else if(commandLine instanceof List) {
+ params.set("DEFAULT".toLowerCase(), (List) commandLine);
+ }
+
+ if(sessionOp != null) {
+ params.set("session", sessionOp);
+ }
+
+ if(sessionId != null) {
+ params.set("session-id", sessionId);
+ }
+
+ report.setMessage(remote.executeCommand(params));
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ return;
+ } catch(CommandException x) {
+ report.setMessage("Remote execution failed: "
+ + x.getMessage());
+ report.setFailureCause(x);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ return;
+ }
+ }
+
+ String cmdName = "";
+ String cmd = "";
+ if(commandLine == null) {
+ cmd = "asadmin-felix-shell";
+ cmdName = cmd;
+ } else if(commandLine instanceof String) {
+ cmd = (String) commandLine;
+ cmdName = cmd;
+ } else if(commandLine instanceof List) {
+ for(Object arg : (List) commandLine) {
+ if(cmd.length() == 0) {
+ // first arg
+ cmd = (String) arg;
+ cmdName = cmd;
+ } else {
+ cmd += " " + (String) arg;
+ }
+ }
+ } else if(commandLine instanceof String[]) {
+ for(Object arg : (String[]) commandLine) {
+ if(cmd.length() == 0) {
+ // first arg
+ cmd = (String) arg;
+ cmdName = cmd;
+ } else {
+ cmd += " " + (String) arg;
+ }
+ }
+ } else {
+ // shouldn't happen...
+ report.setMessage("Unable to deal with argument list of type "
+ + commandLine.getClass().getName());
+ report.setActionExitCode(ActionReport.ExitCode.WARNING);
+ return;
+ }
+
+ // standard output...
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream(512);
+ PrintStream out = new PrintStream(bOut);
+
+ // error output...
+ ByteArrayOutputStream bErr = new ByteArrayOutputStream(512);
+ PrintStream err = new PrintStream(bErr);
+
+ try {
+ Object shell = null;
+
+ ServiceReference sref = ctx.getServiceReference(
+ "org.apache.felix.service.command.CommandProcessor");
+ if(sref != null) {
+ shell = ctx.getService(sref);
+ }
+
+ if(shell == null) {
+ // try with felix...
+ sref = ctx.getServiceReference("org.apache.felix.shell.ShellService");
+ if(sref != null) {
+ shell = ctx.getService(sref);
+ }
+
+ if(shell == null) {
+ report.setMessage("No Shell Service available");
+ report.setActionExitCode(ActionReport.ExitCode.WARNING);
+ return;
+ } else if("asadmin-felix-shell".equals(cmdName)) {
+ out.println("felix");
+ } else {
+ ShellService s = (ShellService) shell;
+ s.executeCommand(cmd, out, err);
+ }
+ } else {
+ // try with gogo...
+ CommandProcessor cp = (CommandProcessor) shell;
+ if(sessionOp == null) {
+ if("asadmin-felix-shell".equals(cmdName)) {
+ out.println("gogo");
+ } else {
+ CommandSession session = cp.createSession(null, out, err);
+ session.execute(cmd);
+ session.close();
+ }
+ } else if("new".equals(sessionOp)) {
+ CommandSession session = cp.createSession(null, null, null);
+ RemoteCommandSession remote = new RemoteCommandSession(session);
+
+ log.log(Level.FINE, "Remote session established: {0}",
+ remote.getId());
+
+ sessions.put(remote.getId(), remote);
+ out.println(remote.getId());
+ } else if("list".equals(sessionOp)) {
+ for(String id : sessions.keySet()) {
+ out.println(id);
+ }
+ } else if("execute".equals(sessionOp)) {
+ RemoteCommandSession remote = sessions.get(sessionId);
+ CommandSession session = remote.attach(null, out, err);
+ session.execute(cmd);
+ remote.detach();
+ } else if("stop".equals(sessionOp)) {
+ RemoteCommandSession remote = sessions.remove(sessionId);
+ CommandSession session = remote.attach(null, out, err);
+ session.close();
+
+ log.log(Level.FINE, "Remote session closed: {0}",
+ remote.getId());
+ }
+ }
+
+ out.flush();
+ err.flush();
+
+ String output = bOut.toString("UTF-8");
+ String errors = bErr.toString("UTF-8");
+ report.setMessage(output);
+
+ if(errors.length() > 0) {
+ report.setMessage(errors);
+ report.setActionExitCode(ActionReport.ExitCode.WARNING);
+ } else {
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ }
+ } catch (Exception ex) {
+ report.setMessage(ex.getMessage());
+ report.setActionExitCode(ActionReport.ExitCode.WARNING);
+ }
+ }
+
+ @Override
+ public void postConstruct() {
+ if(ctx == null) {
+ Bundle me = BundleReference.class.cast(getClass().getClassLoader()).getBundle();
+ ctx = me.getBundleContext();
+ }
+ }
+}
Index: appserver/osgi-platforms/felix-cli-remote/src/main/resources/org/glassfish/osgi/felix/shell/remote/LocalStrings.properties
===================================================================
--- appserver/osgi-platforms/felix-cli-remote/src/main/resources/org/glassfish/osgi/felix/shell/remote/LocalStrings.properties (revision 0)
+++ appserver/osgi-platforms/felix-cli-remote/src/main/resources/org/glassfish/osgi/felix/shell/remote/LocalStrings.properties (revision 0)
@@ -0,0 +1,45 @@
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
+#
+# The contents of this file are subject to the terms of either the GNU
+# General Public License Version 2 only ("GPL") or the Common Development
+# and Distribution License("CDDL") (collectively, the "License"). You
+# may not use this file except in compliance with the License. You can
+# obtain a copy of the License at
+# https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
+# or packager/legal/LICENSE.txt. See the License for the specific
+# language governing permissions and limitations under the License.
+#
+# When distributing the software, include this License Header Notice in each
+# file and include the License file at packager/legal/LICENSE.txt.
+#
+# GPL Classpath Exception:
+# Oracle designates this particular file as subject to the "Classpath"
+# exception as provided by Oracle in the GPL Version 2 section of the License
+# file that accompanied this code.
+#
+# Modifications:
+# If applicable, add the following below the License Header, with the fields
+# enclosed by brackets [] replaced by your own identifying information:
+# "Portions Copyright [year] [name of copyright owner]"
+#
+# Contributor(s):
+# If you wish your version of this file to be governed by only the CDDL or
+# only the GPL Version 2, indicate your decision by adding "[Contributor]
+# elects to include this software in this distribution under the [CDDL or GPL
+# Version 2] license." If you don't indicate a single choice of license, a
+# recipient has the option to distribute your version of this file under
+# either the CDDL, the GPL Version 2 or to extend the choice of license to
+# its licensees as provided above. However, if you add GPL Version 2 code
+# and therefore, elected the GPL Version 2 license, then the option applies
+# only if the new code is made subject to such option by the copyright
+# holder.
+#
+
+felix=Delegates a command line to the Felix Shell Service
+felix.command-line=The full command-line as given inside the Felix Shell
+felix.session=The session operation (one of: new, stop, execute, list)
+felix.session-id=The session id to be specified for the session operations "execute" and "stop"
+felix.instance=The server instance to delegate the command to (the default is the DAS and the DAS must be running to execute some command on another instance)
Index: appserver/osgi-platforms/felix-cli-remote/osgi.bundle
===================================================================
--- appserver/osgi-platforms/felix-cli-remote/osgi.bundle (revision 0)
+++ appserver/osgi-platforms/felix-cli-remote/osgi.bundle (revision 0)
@@ -0,0 +1,53 @@
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
+#
+# The contents of this file are subject to the terms of either the GNU
+# General Public License Version 2 only ("GPL") or the Common Development
+# and Distribution License("CDDL") (collectively, the "License"). You
+# may not use this file except in compliance with the License. You can
+# obtain a copy of the License at
+# https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
+# or packager/legal/LICENSE.txt. See the License for the specific
+# language governing permissions and limitations under the License.
+#
+# When distributing the software, include this License Header Notice in each
+# file and include the License file at packager/legal/LICENSE.txt.
+#
+# GPL Classpath Exception:
+# Oracle designates this particular file as subject to the "Classpath"
+# exception as provided by Oracle in the GPL Version 2 section of the License
+# file that accompanied this code.
+#
+# Modifications:
+# If applicable, add the following below the License Header, with the fields
+# enclosed by brackets [] replaced by your own identifying information:
+# "Portions Copyright [year] [name of copyright owner]"
+#
+# Contributor(s):
+# If you wish your version of this file to be governed by only the CDDL or
+# only the GPL Version 2, indicate your decision by adding "[Contributor]
+# elects to include this software in this distribution under the [CDDL or GPL
+# Version 2] license." If you don't indicate a single choice of license, a
+# recipient has the option to distribute your version of this file under
+# either the CDDL, the GPL Version 2 or to extend the choice of license to
+# its licensees as provided above. However, if you add GPL Version 2 code
+# and therefore, elected the GPL Version 2 license, then the option applies
+# only if the new code is made subject to such option by the copyright
+# holder.
+#
+
+-exportcontents: \
+ org.glassfish.osgi.felix.shell.remote; version=${project.osgi.version}
+
+Import-Package: \
+ *
+
+Bundle-SymbolicName: \
+ ${project.groupId}.${project.artifactId}
+
+# shell packages resolved at runtime, whatever there is...
+DynamicImport-Package: \
+ org.apache.felix.shell, \
+ org.apache.felix.service.command; status="provisional"
Index: appserver/osgi-platforms/felix-cli-remote/pom.xml
===================================================================
--- appserver/osgi-platforms/felix-cli-remote/pom.xml (revision 0)
+++ appserver/osgi-platforms/felix-cli-remote/pom.xml (revision 0)
@@ -0,0 +1,85 @@
+
+
+
+ 4.0.0
+
+ org.glassfish.main.osgi-platforms
+ osgi-console-extensions
+ 4.0-SNAPSHOT
+
+
+ org.glassfish.main.osgi
+ felix-cli-remote
+
+ Admin CLI bridge command to the Felix Shell
+
+
+
+ org.osgi
+ org.osgi.core
+
+
+ org.glassfish.main.common
+ glassfish-api
+ ${project.version}
+
+
+ org.glassfish.main.admin
+ admin-util
+ ${project.version}
+
+
+ org.apache.felix
+ org.apache.felix.shell
+ 1.4.1
+ provided
+
+
+ org.apache.felix
+ org.apache.felix.gogo.runtime
+ 0.8.0
+ provided
+
+
+
Index: appserver/osgi-platforms/felix-cli-interactive/osgi.bundle
===================================================================
--- appserver/osgi-platforms/felix-cli-interactive/osgi.bundle (revision 0)
+++ appserver/osgi-platforms/felix-cli-interactive/osgi.bundle (revision 0)
@@ -0,0 +1,48 @@
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
+#
+# The contents of this file are subject to the terms of either the GNU
+# General Public License Version 2 only ("GPL") or the Common Development
+# and Distribution License("CDDL") (collectively, the "License"). You
+# may not use this file except in compliance with the License. You can
+# obtain a copy of the License at
+# https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
+# or packager/legal/LICENSE.txt. See the License for the specific
+# language governing permissions and limitations under the License.
+#
+# When distributing the software, include this License Header Notice in each
+# file and include the License file at packager/legal/LICENSE.txt.
+#
+# GPL Classpath Exception:
+# Oracle designates this particular file as subject to the "Classpath"
+# exception as provided by Oracle in the GPL Version 2 section of the License
+# file that accompanied this code.
+#
+# Modifications:
+# If applicable, add the following below the License Header, with the fields
+# enclosed by brackets [] replaced by your own identifying information:
+# "Portions Copyright [year] [name of copyright owner]"
+#
+# Contributor(s):
+# If you wish your version of this file to be governed by only the CDDL or
+# only the GPL Version 2, indicate your decision by adding "[Contributor]
+# elects to include this software in this distribution under the [CDDL or GPL
+# Version 2] license." If you don't indicate a single choice of license, a
+# recipient has the option to distribute your version of this file under
+# either the CDDL, the GPL Version 2 or to extend the choice of license to
+# its licensees as provided above. However, if you add GPL Version 2 code
+# and therefore, elected the GPL Version 2 license, then the option applies
+# only if the new code is made subject to such option by the copyright
+# holder.
+#
+
+-exportcontents: \
+ org.glassfish.osgi.felix.shell.interactive; version=${project.osgi.version}
+
+Import-Package: \
+ *
+
+Bundle-SymbolicName: \
+ ${project.groupId}.${project.artifactId}
Index: appserver/osgi-platforms/felix-cli-interactive/pom.xml
===================================================================
--- appserver/osgi-platforms/felix-cli-interactive/pom.xml (revision 0)
+++ appserver/osgi-platforms/felix-cli-interactive/pom.xml (revision 0)
@@ -0,0 +1,106 @@
+
+
+
+ 4.0.0
+
+ org.glassfish.main.osgi-platforms
+ osgi-console-extensions
+ 4.0-SNAPSHOT
+
+
+ org.glassfish.main.osgi
+ felix-cli-interactive
+
+ Admin CLI interactive shell command to the Felix Shell
+ An interactive shell inside asadmin to access a remote OSGi shell
+
+
+
+ CDDL + GPL 1.1
+ http://glassfish.java.net/public/CDDL+GPL_1_1.html
+
+
+ BSD
+
+
+
+
+
+ org.glassfish.main.admin
+ admin-cli
+ ${project.version}
+
+
+ jline
+ jline
+ 2.9
+ provided
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ 2.5.1
+
+
+ copy-libs
+
+ unpack-dependencies
+
+ prepare-package
+
+ jline
+ ${project.build.outputDirectory}
+ true
+
+
+
+
+
+
+
Index: appserver/osgi-platforms/felix-cli-interactive/src/main/java/org/glassfish/osgi/felix/shell/interactive/LocalFelixShellCommand.java
===================================================================
--- appserver/osgi-platforms/felix-cli-interactive/src/main/java/org/glassfish/osgi/felix/shell/interactive/LocalFelixShellCommand.java (revision 0)
+++ appserver/osgi-platforms/felix-cli-interactive/src/main/java/org/glassfish/osgi/felix/shell/interactive/LocalFelixShellCommand.java (revision 0)
@@ -0,0 +1,517 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * http://glassfish.java.net/public/CDDL+GPL_1_1.html
+ * or packager/legal/LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at packager/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ *
+ * This class is forked from com.sun.enterprise.admin.cli.MultimodeCommand
+ *
+ * Original code authors:
+ * केदार(km@dev.java.net)
+ * Bill Shannon
+ */
+package org.glassfish.osgi.felix.shell.interactive;
+
+import com.sun.enterprise.admin.cli.ArgumentTokenizer;
+import com.sun.enterprise.admin.cli.CLICommand;
+import com.sun.enterprise.admin.cli.CLIUtil;
+import com.sun.enterprise.admin.cli.Environment;
+import com.sun.enterprise.admin.cli.MultimodeCommand;
+import com.sun.enterprise.admin.cli.ProgramOptions;
+import com.sun.enterprise.admin.cli.remote.RemoteCLICommand;
+import com.sun.enterprise.admin.util.CommandModelData;
+import com.sun.enterprise.universal.i18n.LocalStringsImpl;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import javax.inject.Inject;
+import jline.console.ConsoleReader;
+import jline.console.completer.Completer;
+import jline.console.completer.NullCompleter;
+import jline.console.completer.StringsCompleter;
+import org.glassfish.api.I18n;
+import org.glassfish.api.Param;
+import org.glassfish.api.admin.CommandException;
+import org.glassfish.api.admin.CommandModel.ParamModel;
+import org.glassfish.api.admin.CommandValidationException;
+import org.glassfish.api.admin.InvalidCommandException;
+import org.glassfish.hk2.api.ActiveDescriptor;
+import org.glassfish.hk2.api.DynamicConfiguration;
+import org.glassfish.hk2.api.DynamicConfigurationService;
+import org.glassfish.hk2.api.PerLookup;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.hk2.utilities.BuilderHelper;
+import org.jvnet.hk2.annotations.Service;
+
+/**
+ * A simple local asadmin sub-command to establish an interactive felix shell.
+ *
+ * @author ancoron
+ */
+@Service(name = "felix-shell")
+@I18n("felix-shell")
+@PerLookup
+public class LocalFelixShellCommand extends CLICommand {
+
+ protected static final String REMOTE_COMMAND = "felix";
+ protected static final String SESSIONID_OPTION = "--session-id";
+ protected static final String SESSION_OPTION = "--session";
+ protected static final String SESSION_OPTION_EXECUTE = "execute";
+ protected static final String SESSION_OPTION_START = "new";
+ protected static final String SESSION_OPTION_STOP = "stop";
+
+ @Inject
+ private ServiceLocator locator;
+
+ @Param(name = "instance", optional = true)
+ private String instance;
+
+ @Param(optional = true, shortName = "f")
+ private File file;
+
+ @Param(name = "printprompt", optional = true)
+ private Boolean printPromptOpt;
+
+ private boolean printPrompt;
+
+ @Param(optional = true)
+ private String encoding;
+
+ private boolean echo; // saved echo flag
+ private RemoteCLICommand cmd; // the remote sub-command
+ private String shellType;
+
+ // re-using existing strings...
+ private static final LocalStringsImpl strings =
+ new LocalStringsImpl(MultimodeCommand.class);
+
+ protected String[] enhanceForTarget(String[] args) {
+ if(instance != null) {
+ String[] targetArgs = new String[args.length + 2];
+ targetArgs[1] = "--instance";
+ targetArgs[2] = instance;
+ System.arraycopy(args, 0, targetArgs, 0, 1);
+ System.arraycopy(args, 1, targetArgs, 3, args.length - 1);
+ args = targetArgs;
+ }
+ return args;
+ }
+
+ protected String[] prepareArguments(String sessionId, String[] args) {
+ if(sessionId != null) {
+ // attach command to remote session...
+ String[] sessionArgs = new String[args.length + 5];
+ sessionArgs[0] = REMOTE_COMMAND;
+ sessionArgs[1] = SESSION_OPTION;
+ sessionArgs[2] = SESSION_OPTION_EXECUTE;
+ sessionArgs[3] = SESSIONID_OPTION;
+ sessionArgs[4] = sessionId;
+ System.arraycopy(args, 0, sessionArgs, 5, args.length);
+ args = sessionArgs;
+ } else {
+ String[] felixArgs = new String[args.length + 1];
+ felixArgs[0] = REMOTE_COMMAND;
+ System.arraycopy(args, 0, felixArgs, 1, args.length);
+ args = felixArgs;
+ }
+ return args;
+ }
+
+ protected String startSession() throws CommandException {
+ String sessionId = null;
+ if("gogo".equals(shellType)) {
+ // start a remote session...
+ String[] args = {REMOTE_COMMAND, SESSION_OPTION,
+ SESSION_OPTION_START};
+ args = enhanceForTarget(args);
+ sessionId = cmd.executeAndReturnOutput(args).trim();
+ }
+ return sessionId;
+ }
+
+ protected int stopSession(String sessionId) throws CommandException {
+ int rc = 0;
+ if(sessionId != null) {
+ // stop the remote session...
+ String[] args = {REMOTE_COMMAND, SESSION_OPTION,
+ SESSION_OPTION_STOP, SESSIONID_OPTION, sessionId};
+ args = enhanceForTarget(args);
+ rc = cmd.execute(args);
+ }
+ return rc;
+ }
+
+ /**
+ * The validate method validates that the type and quantity of
+ * parameters and operands matches the requirements for this
+ * command. The validate method supplies missing options from
+ * the environment.
+ */
+ @Override
+ protected void validate()
+ throws CommandException, CommandValidationException {
+ if (printPromptOpt != null) {
+ printPrompt = printPromptOpt.booleanValue();
+ } else {
+ printPrompt = programOpts.isInteractive();
+ }
+ /*
+ * Save value of --echo because CLICommand will reset it
+ * before calling our executeCommand method but we want it
+ * to also apply to all commands in multimode.
+ */
+ echo = programOpts.isEcho();
+ }
+
+ /**
+ * In the usage message modify the --printprompt option to have a
+ * default based on the --interactive option.
+ */
+ @Override
+ protected Collection usageOptions() {
+ Collection opts = commandModel.getParameters();
+ Set uopts = new LinkedHashSet();
+ ParamModel p = new CommandModelData.ParamModelData("printprompt",
+ boolean.class, true,
+ Boolean.toString(programOpts.isInteractive()));
+ for (ParamModel pm : opts) {
+ if (pm.getName().equals("printprompt")) {
+ uopts.add(p);
+ } else {
+ uopts.add(pm);
+ }
+ }
+ return uopts;
+ }
+
+ @Override
+ protected int executeCommand()
+ throws CommandException, CommandValidationException {
+ ConsoleReader reader = null;
+
+ if(cmd == null) {
+ throw new CommandException("Remote command 'felix' is not available.");
+ }
+
+ programOpts.setEcho(echo); // restore echo flag, saved in validate
+ try {
+ if (encoding != null) {
+ // see Configuration.getEncoding()...
+ System.setProperty("input.encoding", encoding);
+ }
+
+ String[] args = new String[] {REMOTE_COMMAND,
+ "asadmin-felix-shell"};
+ args = enhanceForTarget(args);
+ shellType = cmd.executeAndReturnOutput(args).trim();
+
+ if (file == null) {
+ System.out.println(strings.get("multimodeIntro"));
+ reader = new ConsoleReader(REMOTE_COMMAND,
+ new FileInputStream(FileDescriptor.in), System.out,
+ null);
+ } else {
+ printPrompt = false;
+ if (!file.canRead()) {
+ throw new CommandException("File: " + file
+ + " can not be read");
+ }
+
+ OutputStream out = new OutputStream() {
+
+ @Override
+ public void write(int b) throws IOException {
+ return;
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ return;
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ return;
+ }
+ };
+
+ reader = new ConsoleReader(REMOTE_COMMAND,
+ new FileInputStream(file), out,
+ null);
+ }
+
+ reader.setBellEnabled(false);
+ reader.addCompleter(getCommandCompleter());
+
+ return executeCommands(reader);
+ } catch (IOException e) {
+ throw new CommandException(e);
+ }
+ }
+
+ /**
+ * Get the command completion.
+ *
+ * TODO: make this non-static!
+ * TODO: ask remote for dynamically added commands
+ *
+ * @return The command completer
+ */
+ private Completer getCommandCompleter() {
+ if("gogo".equals(shellType)) {
+ return new StringsCompleter(
+ "bundlelevel",
+ "cd",
+ "frameworklevel",
+ "headers",
+ "help",
+ "inspect",
+ "install",
+ "lb",
+ "log",
+ "ls",
+ "refresh",
+ "resolve",
+ "start",
+ "stop",
+ "uninstall",
+ "update",
+ "which",
+ "cat",
+ "each",
+ "echo",
+ "format",
+ "getopt",
+ "gosh",
+ "grep",
+ "not",
+ "set",
+ "sh",
+ "source",
+ "tac",
+ "telnetd",
+ "type",
+ "until",
+ "deploy",
+ "info",
+ "javadoc",
+ "list",
+ "repos",
+ "source"
+ );
+ } else if("felix".equals(shellType)) {
+ return new StringsCompleter(
+ "exit",
+ "quit",
+ "help",
+ "bundlelevel",
+ "cd",
+ "find",
+ "headers",
+ "inspect",
+ "install",
+ "log",
+ "ps",
+ "refresh",
+ "resolve",
+ "scr",
+ "shutdown",
+ "start",
+ "startlevel",
+ "stop",
+ "sysprop",
+ "uninstall",
+ "update",
+ "version"
+ );
+ }
+
+ return new NullCompleter();
+ }
+
+
+ /**
+ * Read commands from the specified BufferedReader
+ * and execute them. If printPrompt is set, prompt first.
+ *
+ * @return the exit code of the last command executed
+ */
+ private int executeCommands(ConsoleReader reader)
+ throws CommandException, CommandValidationException, IOException {
+ String line = null;
+ int rc = 0;
+
+ /*
+ * Any program options we start with are copied to the environment
+ * to serve as defaults for commands we run, and then we give each
+ * command an empty program options.
+ */
+ programOpts.toEnvironment(env);
+
+ String sessionId = startSession();
+
+ try {
+ for (;;) {
+ if (printPrompt) {
+ line = reader.readLine(shellType + "$ ");
+ } else {
+ line = reader.readLine();
+ }
+
+ if (line == null) {
+ if (printPrompt) {
+ System.out.println();
+ }
+ break;
+ }
+
+ if (line.trim().startsWith("#")) // ignore comment lines
+ {
+ continue;
+ }
+
+ String[] args = null;
+ try {
+ args = getArgs(line);
+ } catch (ArgumentTokenizer.ArgumentException ex) {
+ logger.info(ex.getMessage());
+ continue;
+ }
+
+ if (args.length == 0) {
+ continue;
+ }
+
+ String command = args[0];
+ if (command.trim().length() == 0) {
+ continue;
+ }
+
+ // handle built-in exit and quit commands
+ // XXX - care about their arguments?
+ if (command.equals("exit") || command.equals("quit")) {
+ break;
+ }
+
+ ProgramOptions po = null;
+ try {
+ /*
+ * Every command gets its own copy of program options
+ * so that any program options specified in its
+ * command line options don't effect other commands.
+ * But all commands share the same environment.
+ */
+ po = new ProgramOptions(env);
+ // copy over AsadminMain info
+ po.setClassPath(programOpts.getClassPath());
+ po.setClassName(programOpts.getClassName());
+ // remove the old one and replace it
+ atomicReplace(locator, po);
+
+ args = prepareArguments(sessionId, args);
+
+ args = enhanceForTarget(args);
+
+ String output = cmd.executeAndReturnOutput(args).trim();
+ if(output != null && output.length() > 0) {
+ logger.info(output);
+ }
+ } catch (CommandValidationException cve) {
+ logger.severe(cve.getMessage());
+ logger.severe(cmd.getUsage());
+ rc = ERROR;
+ } catch (InvalidCommandException ice) {
+ // find closest match with local or remote commands
+ logger.severe(ice.getMessage());
+ } catch (CommandException ce) {
+ logger.severe(ce.getMessage());
+ rc = ERROR;
+ } finally {
+ // restore the original program options
+ // XXX - is this necessary?
+ atomicReplace(locator, programOpts);
+ }
+
+ CLIUtil.writeCommandToDebugLog(name, env, args, rc);
+ }
+ } finally {
+ // what if something breaks on the wire?
+ rc = stopSession(sessionId);
+ }
+ return rc;
+ }
+
+ private static void atomicReplace(ServiceLocator locator, ProgramOptions options) {
+ DynamicConfigurationService dcs = locator.getService(DynamicConfigurationService.class);
+ DynamicConfiguration config = dcs.createDynamicConfiguration();
+
+ config.addUnbindFilter(BuilderHelper.createContractFilter(ProgramOptions.class.getName()));
+ ActiveDescriptor desc = BuilderHelper.createConstantDescriptor(
+ options, null, ProgramOptions.class);
+ config.addActiveDescriptor(desc);
+
+ config.commit();
+ }
+
+ private String[] getArgs(String line)
+ throws ArgumentTokenizer.ArgumentException {
+ List args = new ArrayList();
+ ArgumentTokenizer t = new ArgumentTokenizer(line);
+ while (t.hasMoreTokens()) {
+ args.add(t.nextToken());
+ }
+ return args.toArray(new String[args.size()]);
+ }
+
+ @Override
+ public void postConstruct() {
+ super.postConstruct();
+ try {
+ cmd = new RemoteCLICommand(REMOTE_COMMAND,
+ locator.getService(ProgramOptions.class),
+ locator.getService(Environment.class));
+ } catch (CommandException ex) {
+ // ignore - will be handled by execute()
+ }
+ }
+}
Index: appserver/osgi-platforms/felix-cli-interactive/src/main/resources/org/glassfish/osgi/felix/shell/interactive/LocalStrings.properties
===================================================================
--- appserver/osgi-platforms/felix-cli-interactive/src/main/resources/org/glassfish/osgi/felix/shell/interactive/LocalStrings.properties (revision 0)
+++ appserver/osgi-platforms/felix-cli-interactive/src/main/resources/org/glassfish/osgi/felix/shell/interactive/LocalStrings.properties (revision 0)
@@ -0,0 +1,46 @@
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
+#
+# The contents of this file are subject to the terms of either the GNU
+# General Public License Version 2 only ("GPL") or the Common Development
+# and Distribution License("CDDL") (collectively, the "License"). You
+# may not use this file except in compliance with the License. You can
+# obtain a copy of the License at
+# http://glassfish.java.net/public/CDDL+GPL_1_1.html
+# or packager/legal/LICENSE.txt. See the License for the specific
+# language governing permissions and limitations under the License.
+#
+# When distributing the software, include this License Header Notice in each
+# file and include the License file at packager/legal/LICENSE.txt.
+#
+# GPL Classpath Exception:
+# Oracle designates this particular file as subject to the "Classpath"
+# exception as provided by Oracle in the GPL Version 2 section of the License
+# file that accompanied this code.
+#
+# Modifications:
+# If applicable, add the following below the License Header, with the fields
+# enclosed by brackets [] replaced by your own identifying information:
+# "Portions Copyright [year] [name of copyright owner]"
+#
+# Contributor(s):
+# If you wish your version of this file to be governed by only the CDDL or
+# only the GPL Version 2, indicate your decision by adding "[Contributor]
+# elects to include this software in this distribution under the [CDDL or GPL
+# Version 2] license." If you don't indicate a single choice of license, a
+# recipient has the option to distribute your version of this file under
+# either the CDDL, the GPL Version 2 or to extend the choice of license to
+# its licensees as provided above. However, if you add GPL Version 2 code
+# and therefore, elected the GPL Version 2 license, then the option applies
+# only if the new code is made subject to such option by the copyright
+# holder.
+#
+# Original author: Ancoron Luciferis
+#
+
+felix-shell=An interactive Shell to access a remote Felix Shell Service
+felix-shell.instance=The server instance to delegate the commands to (the default is the DAS and the DAS must be running to execute some command on another instance)
+felix-shell.file=A file containing commands to be executed (the shell is stopped after processing all commands in that file)
+felix-shell.printprompt=Print the shell prompt or not (enabled by default)
Index: appserver/osgi-platforms/pom.xml
===================================================================
--- appserver/osgi-platforms/pom.xml (revision 56188)
+++ appserver/osgi-platforms/pom.xml (working copy)
@@ -58,6 +58,8 @@
felix-webconsole-extension
glassfish-osgi-console-plugin
glassfish-osgi-console-plugin-l10n
+ felix-cli-remote
+ felix-cli-interactive
Index: appserver/packager/glassfish-osgi/pom.xml
===================================================================
--- appserver/packager/glassfish-osgi/pom.xml (revision 56188)
+++ appserver/packager/glassfish-osgi/pom.xml (working copy)
@@ -90,7 +90,11 @@
compile
runtime
${packager.artifact.excludes}
- org.glassfish.fighterfish,org.apache.felix
+
+ org.glassfish.fighterfish,
+ org.apache.felix,
+ org.glassfish.main.osgi
+
true
@@ -172,6 +176,16 @@
org.apache.felix
org.apache.felix.eventadmin
+
+ org.glassfish.main.osgi
+ felix-cli-remote
+ ${project.version}
+
+
+ org.glassfish.main.osgi
+ felix-cli-interactive
+ ${project.version}
+
Index: appserver/packager/glassfish-osgi/build.xml
===================================================================
--- appserver/packager/glassfish-osgi/build.xml (revision 56188)
+++ appserver/packager/glassfish-osgi/build.xml (working copy)
@@ -71,6 +71,12 @@
+
+
+
+
Index: nucleus/packager/nucleus-osgi/pom.xml
===================================================================
--- nucleus/packager/nucleus-osgi/pom.xml (revision 56188)
+++ nucleus/packager/nucleus-osgi/pom.xml (working copy)
@@ -85,13 +85,6 @@
org.apache.felix
- org.apache.felix.shell.remote
- 1.1.2
- jar
- ${temp.stagedir}
-
-
- org.apache.felix
org.apache.felix.gogo.runtime
0.8.0
jar
Index: nucleus/osgi-platforms/felix/src/main/resources/glassfish/config/osgi.properties
===================================================================
--- nucleus/osgi-platforms/felix/src/main/resources/glassfish/config/osgi.properties (revision 56188)
+++ nucleus/osgi-platforms/felix/src/main/resources/glassfish/config/osgi.properties (working copy)
@@ -200,7 +200,7 @@
${com.sun.aas.installRootURI}modules/org.apache.felix.gogo.runtime.jar \
${com.sun.aas.installRootURI}modules/org.apache.felix.gogo.command.jar \
${com.sun.aas.installRootURI}modules/org.apache.felix.gogo.shell.jar \
- ${com.sun.aas.installRootURI}modules/org.apache.felix.shell.remote.jar
+ ${com.sun.aas.installRootURI}modules/felix-cli-remote.jar
# This property is used to configure a list of bundles to be started by our autoprocessor.
# Eventual activation of the bundles depend on bundle's start level and activation policy.
@@ -223,7 +223,7 @@
# to set the start level of the OSGi framework once server is up and running so that
# optional services can start. The initial start level of framework is controlled using
# the standard framework property called org.osgi.framework.startlevel.beginning
-glassfish.osgi.start.level.final=2
+glassfish.osgi.start.level.final=3
# What should be the initial start level of framework.
# For performance reason, initially we set the start level to 1 so that no optional