package com.github.dynamicextensionsalfresco.controlpanel;
import com.github.dynamicextensionsalfresco.controlpanel.template.TemplateBundle;
import com.github.dynamicextensionsalfresco.controlpanel.template.TemplateServiceReference;
import com.github.dynamicextensionsalfresco.controlpanel.template.Variables;
import com.github.dynamicextensionsalfresco.osgi.RepositoryStoreService;
import com.github.dynamicextensionsalfresco.webscripts.annotations.Attribute;
import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication;
import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType;
import com.github.dynamicextensionsalfresco.webscripts.annotations.Cache;
import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod;
import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri;
import com.github.dynamicextensionsalfresco.webscripts.annotations.UriVariable;
import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.NodeService;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.launch.Framework;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanIsAbstractException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* Handles requests for the configuration page.
*
* @author Laurens Fridael
*
*/
@Component
@WebScript(baseUri = "/dynamic-extensions/container", defaultFormat = "html", families = "control panel")
@Authentication(AuthenticationType.ADMIN)
@Cache(neverCache = true)
public class Container extends AbstractControlPanelHandler {
/* Dependencies */
@Autowired
private BundleHelper bundleHelper;
@Autowired
private FileFolderService fileFolderService;
@Autowired
private NodeService nodeService;
@Autowired
private RepositoryStoreService repositoryStoreService;
/* Main operations */
@Uri(method = HttpMethod.GET)
public Map<String, Object> index() {
return Collections.emptyMap();
}
@Uri(method = HttpMethod.GET, value = "/system-packages")
public Map<String, Object> systemPackages() {
return model(Variables.SYSTEM_PACKAGES, getSystemPackages());
}
@Uri(method = HttpMethod.GET, value = "/services")
public Map<String, Object> services() {
return model(Variables.SERVICES_BY_BUNDLE, getTemplateServicesByBundle());
}
@Uri(method = HttpMethod.GET, value = "/services/bundle/{bundleid}/{serviceIndex}")
public Map<String, Object> service(@UriVariable final long bundleid, @UriVariable int serviceIndex) {
final List<TemplateBundle> servicesByBundle = getTemplateServicesByBundle();
TemplateServiceReference serviceReferences = null;
for (TemplateBundle templateBundle : servicesByBundle) {
if (templateBundle.getBundleId() == bundleid) {
serviceReferences = templateBundle.getServices().get(serviceIndex);
break;
}
}
final Object context;
if (serviceReferences != null) {
@SuppressWarnings("unchecked")
final ServiceReference<Object> serviceReference = serviceReferences.getServiceReference();
context = bundleHelper.getBundle(bundleid).getBundleContext().getService(serviceReference);
if (context instanceof ApplicationContext) {
ApplicationContext applicationContext = (ApplicationContext)context;
final String[] definitionNames = applicationContext.getBeanDefinitionNames();
final Map<String,String> beans = new HashMap<String, String>(definitionNames.length);
for (String name : definitionNames) {
try {
final Object instance = applicationContext.getBean(name);
final String className;
if (AopUtils.isAopProxy(instance)) {
// remark: getTargetClass does not resolve for non Spring Proxies
className = "[Spring Proxy] " + AopUtils.getTargetClass(instance).getName();
} else if (Proxy.isProxyClass(instance.getClass())) {
className = "[Java Proxy] " + Proxy.getInvocationHandler(instance).getClass().getName() + " -> " + Arrays.toString(ClassUtils.getAllInterfaces(instance));
} else {
className = instance.getClass().getCanonicalName();
}
beans.put(name, className);
} catch (BeanIsAbstractException ignore) {}
}
return model("contextBeans", beans);
}
throw new IllegalArgumentException("Service is not a Spring ApplicationContext, but a " + context.getClass().getName());
} else {
throw new IllegalArgumentException(String.format("No service found for bundle %s at index %s.",bundleid, serviceIndex));
}
}
/* Utility operations */
@SuppressWarnings("rawtypes")
protected List<TemplateBundle> getTemplateServicesByBundle() {
final Map<Long, List<ServiceReference<Object>>> servicesByBundleId = getServicesByBundleId();
final List<TemplateBundle> templateBundles = new ArrayList<TemplateBundle>(servicesByBundleId.keySet().size());
for (final Entry<Long, List<ServiceReference<Object>>> entry : servicesByBundleId.entrySet()) {
final Bundle bundle = bundleHelper.getBundle(entry.getKey());
final List<ServiceReference<Object>> services = servicesByBundleId.get(entry.getKey());
templateBundles.add(new TemplateBundle(bundle, services));
}
return templateBundles;
}
@SuppressWarnings("unchecked")
protected Map<Long, List<ServiceReference<Object>>> getServicesByBundleId() {
final Map<Long, List<ServiceReference<Object>>> servicesByBundleId = new LinkedHashMap<Long, List<ServiceReference<Object>>>();
final ServiceReference<?>[] allServices = bundleHelper.getAllServices();
if (allServices != null) {
for (final ServiceReference serviceReference : allServices) {
final long bundleId = serviceReference.getBundle().getBundleId();
if (servicesByBundleId.containsKey(bundleId) == false) {
servicesByBundleId.put(bundleId, new ArrayList<ServiceReference<Object>>());
}
servicesByBundleId.get(bundleId).add(serviceReference);
}
}
return servicesByBundleId;
}
/* Reference data */
@Attribute(Variables.CAN_RESTART_FRAMEWORK)
protected boolean canRestartFramework() {
return osgiConfiguration.getFrameworkRestartEnabled();
}
@Attribute(Variables.SYSTEM_PACKAGE_CACHE_EXISTS)
protected boolean systemPackageCacheExists() {
return (getConfiguration().getSystemPackageCache().isFile());
}
@Attribute(Variables.REPOSITORY_STORE_LOCATION)
protected String getRepositoryStoreLocation() {
return bundleHelper.getBundleRepositoryLocation();
}
/* Utility operations */
protected void restartFramework(final Framework framework) {
try {
framework.stop();
framework.waitForStop(0);
framework.start();
} catch (final BundleException ignore) {
} catch (final InterruptedException ignore) {
}
}
}