package org.srpingframework.roo.osgi.gogo.commands;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.lang3.Validate;
import org.apache.felix.bundlerepository.Capability;
import org.apache.felix.bundlerepository.Property;
import org.apache.felix.bundlerepository.Repository;
import org.apache.felix.bundlerepository.RepositoryAdmin;
import org.apache.felix.bundlerepository.Resource;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.subsystem.Subsystem;
import org.springframework.roo.support.logging.HandlerUtils;
/**
*
* Adding Subsystem Gogo commands
*
* @author Juan Carlos GarcĂa
* @since 2.0
*/
@Component(immediate = true)
@Service
public class SubsystemCommands implements BundleActivator {
private static final Logger LOGGER = HandlerUtils.getLogger(SubsystemCommands.class);
private static final String REPOSITORY_DEPENDENCY_CAPABILITY_NAME = "repositories";
private static final String SUBSYSTEM_DEPENDENCY_CAPABILITY_NAME = "subsystems";
private BundleContext bundleContext;
private RepositoryAdmin repositoryAdmin;
private List<Repository> repositories;
// TODO: Improve Gogo commands ROO implementation using
// apache felix @Command annotation
protected void activate(final ComponentContext context) {
try {
start(context.getBundleContext());
} catch (Exception e) {
e.printStackTrace();
}
}
public void start(BundleContext context) throws Exception {
bundleContext = context;
Dictionary<String, Object> props = new Hashtable<String, Object>();
props.put("osgi.command.function", new String[] {"deploy", "install", "uninstall", "start",
"stop", "list",});
props.put("osgi.command.scope", "subsystem");
context.registerService(getClass().getName(), this, props);
}
public void deploy(String symbolicName) throws Exception {
repositories = new ArrayList<Repository>();
// Getting all installed repositories
populateRepositories();
// Getting subsystem resource from OBR Repository by resource
// symbolicName
Resource subsystemResource = getSubsystemResource(symbolicName);
// Install related repositories or related subsystems if needed
LOGGER.log(Level.INFO, "Subsystem dependency manager started.");
LOGGER.log(Level.INFO, "");
installSubsystemDependencies(subsystemResource);
LOGGER.log(Level.INFO, "Subsystem dependency manager finished.");
LOGGER.log(Level.INFO, "");
// Install subsystem using symbolicName
Subsystem subsystem = install(subsystemResource.getURI());
// Starting installed subsystem
start(subsystem.getSubsystemId());
}
public Subsystem install(String url) {
LOGGER.log(Level.INFO, "Installing subsystem...");
Subsystem rootSubsystem = getSubsystem(0);
Subsystem s = rootSubsystem.install(url);
LOGGER.log(Level.INFO, "Subsystem successfully installed: " + s.getSymbolicName() + "; id: "
+ s.getSubsystemId());
LOGGER.log(Level.INFO, " ");
return s;
}
public void uninstall(long id) {
LOGGER.log(Level.INFO, "Uninstalling subsystem: " + id);
LOGGER.log(Level.INFO, " ");
Subsystem subsystem = getSubsystem(id);
subsystem.uninstall();
LOGGER.log(Level.INFO, "Subsystem successfully uninstalled: " + subsystem.getSymbolicName()
+ "; id: " + subsystem.getSubsystemId());
LOGGER.log(Level.INFO, " ");
}
public void start(long id) {
LOGGER.log(Level.INFO, "Starting subsystem: " + id);
Subsystem subsystem = getSubsystem(id);
subsystem.start();
LOGGER.log(Level.INFO, "Subsystem successfully started: " + subsystem.getSymbolicName()
+ "; id: " + subsystem.getSubsystemId());
LOGGER.log(Level.INFO, " ");
}
public void stop(long id) {
LOGGER.log(Level.INFO, "Stopping subsystem: " + id);
LOGGER.log(Level.INFO, " ");
Subsystem subsystem = getSubsystem(id);
subsystem.stop();
LOGGER.log(Level.INFO, "Subsystem successfully stopped: " + subsystem.getSymbolicName()
+ "; id: " + subsystem.getSubsystemId());
LOGGER.log(Level.INFO, " ");
}
public void list() throws InvalidSyntaxException {
Map<Long, String> subsystems = new TreeMap<Long, String>();
for (ServiceReference<Subsystem> ref : bundleContext
.getServiceReferences(Subsystem.class, null)) {
Subsystem s = bundleContext.getService(ref);
if (s != null) {
subsystems.put(
s.getSubsystemId(),
String.format("%d\t%s\t%s %s", s.getSubsystemId(), s.getState(), s.getSymbolicName(),
s.getVersion()));
}
}
for (String entry : subsystems.values()) {
LOGGER.log(Level.INFO, entry);
}
}
/**
* Method that checks capabilities of selected subsystem resource and if appears any related repository
* or any related subsystem are going to be installed.
*
* @param subsystemResource
* @throws Exception
*/
private void installSubsystemDependencies(Resource subsystemResource) throws Exception {
// Getting capabilites of subsytem resource
Capability[] capabilities = subsystemResource.getCapabilities();
// Creating lists to save repositories and subsystems
List<Capability> repositoriesCapability = new ArrayList<Capability>();
List<Capability> subsystemsCapability = new ArrayList<Capability>();
LOGGER.log(Level.INFO, "Getting 'Roo Addon Suite' dependencies...");
LOGGER.log(Level.INFO, " ");
// Saving repositories and subsystems
for (Capability capability : capabilities) {
if (capability.getName().equals(REPOSITORY_DEPENDENCY_CAPABILITY_NAME)) {
repositoriesCapability.add(capability);
} else if (capability.getName().equals(SUBSYSTEM_DEPENDENCY_CAPABILITY_NAME)) {
subsystemsCapability.add(capability);
}
}
showDependenciesInfo(repositoriesCapability, subsystemsCapability);
// If selected Roo Addon Suite doesn't have any dependency
// continue installing individual 'Roo Addon Suite'
if (repositoriesCapability.isEmpty() && subsystemsCapability.isEmpty()) {
return;
}
// Installing repositories if needed
if (!repositoriesCapability.isEmpty()) {
LOGGER.log(Level.INFO, " Adding repositories to Spring Roo installation");
LOGGER.log(Level.INFO, " ----------------------------------------------------------");
LOGGER.log(Level.INFO, "");
// Adding all repositories in order
for (Capability repositoryCapability : repositoriesCapability) {
Property[] repositoryList = repositoryCapability.getProperties();
for (Property repository : repositoryList) {
String repoURL = repository.getValue();
getRepositoryAdmin().addRepository(repoURL);
LOGGER.log(Level.INFO, " " + repoURL + " added");
}
}
LOGGER.log(Level.INFO, "");
}
// Installing subsystems if needed
if (!subsystemsCapability.isEmpty()) {
LOGGER.log(Level.INFO, " Installing subsystems into Spring Roo installation");
LOGGER.log(Level.INFO, " ----------------------------------------------------------");
LOGGER.log(Level.INFO, "");
// Installing subsystems in order
for (Capability subsystemCapability : subsystemsCapability) {
Property[] subsystemList = subsystemCapability.getProperties();
for (Property subsystem : subsystemList) {
String subsystemURL = subsystem.getValue();
getSubsystem(0).install(subsystemURL);
LOGGER.log(Level.INFO, " " + subsystemURL + " installed");
}
}
LOGGER.log(Level.INFO, "");
}
}
/**
* Method to show Subsystem dependencies on Spring Roo Shell
*
* @param repositories
* @param subsystems
*/
private void showDependenciesInfo(List<Capability> repositories, List<Capability> subsystems) {
// If empty dependencies
if (repositories.isEmpty() && subsystems.isEmpty()) {
LOGGER.log(Level.INFO, " 0 dependencies were found on selected 'Roo Addon Suite'");
LOGGER.log(Level.INFO, "");
return;
}
// If selected subsystem has some repositories dependency
if (!repositories.isEmpty()) {
LOGGER.log(Level.INFO, " Repository Dependencies");
LOGGER.log(Level.INFO, " ---------------------------------");
for (Capability repo : repositories) {
Property[] repositoriesProperties = repo.getProperties();
for (Property prop : repositoriesProperties) {
LOGGER.log(Level.INFO, " " + prop.getValue());
}
LOGGER.log(Level.INFO, " ");
LOGGER.log(Level.INFO, String.format(
" %s repository dependencies were found on selected 'Roo Addon Suite'",
repositoriesProperties.length));
LOGGER.log(Level.INFO, "");
}
}
// If selected subsystem has some subsystem dependency
if (!subsystems.isEmpty()) {
LOGGER.log(Level.INFO, " Subsystem Dependencies");
LOGGER.log(Level.INFO, " ---------------------------------");
for (Capability subsystem : subsystems) {
Property[] subsystemProperties = subsystem.getProperties();
for (Property prop : subsystemProperties) {
LOGGER.log(Level.INFO, " " + prop.getValue());
}
LOGGER.log(Level.INFO, " ");
LOGGER.log(Level.INFO, String.format(
" %s subsystem dependencies were found on selected 'Roo Addon Suite'",
subsystemProperties.length));
LOGGER.log(Level.INFO, "");
}
}
}
/**
* Method to populate current Repositories using OSGi Serive
*/
private void populateRepositories() {
// Cleaning Repositories
repositories.clear();
// Validating that RepositoryAdmin exists
Validate.notNull(getRepositoryAdmin(), "RepositoryAdmin not found");
for (Repository repo : getRepositoryAdmin().listRepositories()) {
repositories.add(repo);
}
}
/**
* Method to get RepositoryAdmin Service implementation
*
* @return
*/
public RepositoryAdmin getRepositoryAdmin() {
if (repositoryAdmin == null) {
// Get all Services implement RepositoryAdmin interface
try {
ServiceReference<?>[] references =
bundleContext.getAllServiceReferences(RepositoryAdmin.class.getName(), null);
for (ServiceReference<?> ref : references) {
repositoryAdmin = (RepositoryAdmin) bundleContext.getService(ref);
return repositoryAdmin;
}
return null;
} catch (InvalidSyntaxException e) {
LOGGER.warning("Cannot load RepositoryAdmin on SubsystemCommands.");
return null;
}
} else {
return repositoryAdmin;
}
}
private Subsystem getSubsystem(long id) {
try {
for (ServiceReference<Subsystem> ref : bundleContext.getServiceReferences(Subsystem.class,
"(subsystem.id=" + id + ")")) {
Subsystem svc = bundleContext.getService(ref);
if (svc != null)
return svc;
}
} catch (InvalidSyntaxException e) {
throw new RuntimeException(e);
}
throw new RuntimeException("Unable to find subsystem " + id);
}
/**
* Method to obtain subsystem resource by symbolicName
*
* @return
*/
private Resource getSubsystemResource(String symbolicName) {
for (Repository repo : repositories) {
// Getting all resources from every repo
Resource[] repoResources = repo.getResources();
for (Resource resource : repoResources) {
// Getting resource
if (resource.getSymbolicName().equals(symbolicName)) {
return resource;
}
}
}
throw new RuntimeException("Unable to find any Roo Addon Suite on installed repositories "
+ "with symbolic name " + symbolicName);
}
public void stop(BundleContext context) throws Exception {}
}