package org.argeo.cms.internal.runtime;
-import java.io.IOException;
-import java.net.URL;
-import java.util.Dictionary;
+import static org.argeo.api.cms.CmsConstants.CONTEXT_PATH;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.argeo.api.cms.CmsConstants;
import org.argeo.api.cms.CmsDeployment;
import org.argeo.api.cms.CmsLog;
import org.argeo.api.cms.CmsState;
-import org.argeo.cms.internal.osgi.DeployConfig;
-import org.osgi.service.http.HttpService;
+import org.argeo.cms.CmsDeployProperty;
+import org.argeo.cms.CmsSshd;
+import org.argeo.cms.internal.http.CmsAuthenticator;
+import org.argeo.cms.internal.http.PublicCmsAuthenticator;
+
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
-/** Implementation of a CMS deployment. */
+/** Reference implementation of {@link CmsDeployment}. */
public class CmsDeploymentImpl implements CmsDeployment {
private final CmsLog log = CmsLog.getLog(getClass());
-// private final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext();
-// private Long availableSince;
+ private CmsState cmsState;
- // Readiness
-// private boolean nodeAvailable = false;
-// private boolean userAdminAvailable = false;
+ // Expectations
private boolean httpExpected = false;
-// private boolean httpAvailable = false;
- private HttpService httpService;
+ private boolean sshdExpected = false;
- private CmsState cmsState;
- private DeployConfig deployConfig;
-
- public CmsDeploymentImpl() {
-// ServiceReference<NodeState> nodeStateSr = bc.getServiceReference(NodeState.class);
-// if (nodeStateSr == null)
-// throw new CmsException("No node state available");
+ // HTTP
+ private HttpServer httpServer;
+ private Map<String, HttpHandler> httpHandlers = new TreeMap<>();
+ private Map<String, CmsAuthenticator> httpAuthenticators = new TreeMap<>();
-// NodeState nodeState = bc.getService(nodeStateSr);
-// cleanState = nodeState.isClean();
+ // SSHD
+ private CmsSshd cmsSshd;
-// nodeHttp = new NodeHttp();
- initTrackers();
+ public void start() {
+ log.debug(() -> "CMS deployment available");
}
- private void initTrackers() {
-// ServiceTracker<?, ?> httpSt = new ServiceTracker<HttpService, HttpService>(bc, HttpService.class, null) {
-//
-// @Override
-// public HttpService addingService(ServiceReference<HttpService> sr) {
-// httpAvailable = true;
-// Object httpPort = sr.getProperty("http.port");
-// Object httpsPort = sr.getProperty("https.port");
-// log.info(httpPortsMsg(httpPort, httpsPort));
-// checkReadiness();
-// return super.addingService(sr);
-// }
-// };
-// // httpSt.open();
-// KernelUtils.asyncOpen(httpSt);
-
-// ServiceTracker<?, ?> userAdminSt = new ServiceTracker<UserAdmin, UserAdmin>(bc, UserAdmin.class, null) {
-// @Override
-// public UserAdmin addingService(ServiceReference<UserAdmin> reference) {
-// UserAdmin userAdmin = super.addingService(reference);
-// addStandardSystemRoles(userAdmin);
-// userAdminAvailable = true;
-// checkReadiness();
-// return userAdmin;
-// }
-// };
-// // userAdminSt.open();
-// KernelUtils.asyncOpen(userAdminSt);
-
-// ServiceTracker<?, ?> confAdminSt = new ServiceTracker<ConfigurationAdmin, ConfigurationAdmin>(bc,
-// ConfigurationAdmin.class, null) {
-// @Override
-// public ConfigurationAdmin addingService(ServiceReference<ConfigurationAdmin> reference) {
-// ConfigurationAdmin configurationAdmin = bc.getService(reference);
-//// boolean isClean;
-//// try {
-//// Configuration[] confs = configurationAdmin
-//// .listConfigurations("(service.factoryPid=" + CmsConstants.NODE_USER_ADMIN_PID + ")");
-//// isClean = confs == null || confs.length == 0;
-//// } catch (Exception e) {
-//// throw new IllegalStateException("Cannot analyse clean state", e);
-//// }
-// deployConfig = new DeployConfig(configurationAdmin, isClean);
-// Activator.registerService(CmsDeployment.class, CmsDeploymentImpl.this, null);
-//// JcrInitUtils.addToDeployment(CmsDeployment.this);
-// httpExpected = deployConfig.getProps(KernelConstants.JETTY_FACTORY_PID, "default") != null;
-// try {
-// Configuration[] configs = configurationAdmin
-// .listConfigurations("(service.factoryPid=" + CmsConstants.NODE_USER_ADMIN_PID + ")");
-//
-// boolean hasDomain = false;
-// for (Configuration config : configs) {
-// Object realm = config.getProperties().get(UserAdminConf.realm.name());
-// if (realm != null) {
-// log.debug("Found realm: " + realm);
-// hasDomain = true;
-// }
-// }
-// if (hasDomain) {
-// loadIpaJaasConfiguration();
-// }
-// } catch (Exception e) {
-// throw new IllegalStateException("Cannot initialize config", e);
-// }
-// return super.addingService(reference);
-// }
-// };
-// // confAdminSt.open();
-// KernelUtils.asyncOpen(confAdminSt);
+ public void stop() {
}
- public void start() {
- httpExpected = deployConfig.getProps(KernelConstants.JETTY_FACTORY_PID, "default") != null;
- if (deployConfig.hasDomain()) {
- loadIpaJaasConfiguration();
- }
-
-// while (!isHttpAvailableOrNotExpected()) {
-// try {
-// Thread.sleep(100);
-// } catch (InterruptedException e) {
-// log.error("Interrupted while waiting for http");
-// }
-// }
- }
+ public void setCmsState(CmsState cmsState) {
+ this.cmsState = cmsState;
- public void addFactoryDeployConfig(String factoryPid, Dictionary<String, Object> props) {
- deployConfig.putFactoryDeployConfig(factoryPid, props);
- deployConfig.save();
- try {
- deployConfig.loadConfigs();
- } catch (IOException e) {
- throw new IllegalStateException(e);
- }
- }
+ String httpPort = this.cmsState.getDeployProperty(CmsDeployProperty.HTTP_PORT.getProperty());
+ String httpsPort = this.cmsState.getDeployProperty(CmsDeployProperty.HTTPS_PORT.getProperty());
+ httpExpected = httpPort != null || httpsPort != null;
- public Dictionary<String, Object> getProps(String factoryPid, String cn) {
- return deployConfig.getProps(factoryPid, cn);
+ String sshdPort = this.cmsState.getDeployProperty(CmsDeployProperty.SSHD_PORT.getProperty());
+ sshdExpected = sshdPort != null;
}
-// private void addStandardSystemRoles(UserAdmin userAdmin) {
-// // we assume UserTransaction is already available (TODO make it more robust)
-// WorkTransaction userTransaction = bc.getService(bc.getServiceReference(WorkTransaction.class));
-// try {
-// userTransaction.begin();
-// Role adminRole = userAdmin.getRole(CmsConstants.ROLE_ADMIN);
-// if (adminRole == null) {
-// adminRole = userAdmin.createRole(CmsConstants.ROLE_ADMIN, Role.GROUP);
-// }
-// if (userAdmin.getRole(CmsConstants.ROLE_USER_ADMIN) == null) {
-// Group userAdminRole = (Group) userAdmin.createRole(CmsConstants.ROLE_USER_ADMIN, Role.GROUP);
-// userAdminRole.addMember(adminRole);
-// }
-// userTransaction.commit();
-// } catch (Exception e) {
-// try {
-// userTransaction.rollback();
-// } catch (Exception e1) {
-// // silent
-// }
-// throw new IllegalStateException("Cannot add standard system roles", e);
-// }
-// }
-
- public boolean isHttpAvailableOrNotExpected() {
- return (httpExpected ? httpService != null : true);
+ public void setHttpServer(HttpServer httpServer) {
+ this.httpServer = httpServer;
+ // create contexts whose handles had already been published
+ for (String contextPath : httpHandlers.keySet()) {
+ HttpHandler httpHandler = httpHandlers.get(contextPath);
+ CmsAuthenticator authenticator = httpAuthenticators.get(contextPath);
+ createHttpContext(contextPath, httpHandler, authenticator);
+ }
}
- private void loadIpaJaasConfiguration() {
- if (System.getProperty(KernelConstants.JAAS_CONFIG_PROP) == null) {
- String jaasConfig = KernelConstants.JAAS_CONFIG_IPA;
- URL url = getClass().getClassLoader().getResource(jaasConfig);
- KernelUtils.setJaasConfiguration(url);
- log.debug("Set IPA JAAS configuration.");
+ public void addHttpHandler(HttpHandler httpHandler, Map<String, String> properties) {
+ final String contextPath = properties.get(CONTEXT_PATH);
+ if (contextPath == null) {
+ log.warn("Property " + CONTEXT_PATH + " not set on HTTP handler " + properties + ". Ignoring it.");
+ return;
+ }
+ boolean isPublic = Boolean.parseBoolean(properties.get(CmsConstants.CONTEXT_PUBLIC));
+ CmsAuthenticator authenticator = isPublic ? new PublicCmsAuthenticator() : new CmsAuthenticator();
+ httpHandlers.put(contextPath, httpHandler);
+ httpAuthenticators.put(contextPath, authenticator);
+ if (httpServer == null) {
+ return;
+ } else {
+ createHttpContext(contextPath, httpHandler, authenticator);
}
}
- public void stop() {
-// if (nodeHttp != null)
-// nodeHttp.destroy();
-
-// try {
-// JettyConfigurator.stopServer(KernelConstants.DEFAULT_JETTY_SERVER);
-// } catch (Exception e) {
-// log.error("Cannot stop default Jetty server.", e);
-// }
-
- if (deployConfig != null) {
- deployConfig.save();
- // new Thread(() -> deployConfig.save(), "Save Argeo Deploy Config").start();
- }
+ public void createHttpContext(String contextPath, HttpHandler httpHandler, CmsAuthenticator authenticator) {
+ HttpContext httpContext = httpServer.createContext(contextPath);
+ // we want to set the authenticator BEFORE the handler actually becomes active
+ httpContext.setAuthenticator(authenticator);
+ httpContext.setHandler(httpHandler);
+ log.debug(() -> "Added handler " + contextPath + " : " + httpHandler.getClass().getName());
}
- public void setDeployConfig(DeployConfig deployConfig) {
- this.deployConfig = deployConfig;
+ public void removeHttpHandler(HttpHandler httpHandler, Map<String, String> properties) {
+ final String contextPath = properties.get(CmsConstants.CONTEXT_PATH);
+ if (contextPath == null)
+ return; // ignore silently
+ httpHandlers.remove(contextPath);
+ if (httpServer == null)
+ return;
+ httpServer.removeContext(contextPath);
+ log.debug(() -> "Removed handler " + contextPath + " : " + httpHandler.getClass().getName());
}
- public void setCmsState(CmsState cmsState) {
- this.cmsState = cmsState;
+ public boolean allExpectedServicesAvailable() {
+ if (httpExpected && httpServer == null)
+ return false;
+ if (sshdExpected && cmsSshd == null)
+ return false;
+ return true;
}
- public void setHttpService(HttpService httpService) {
- this.httpService = httpService;
+ public void setCmsSshd(CmsSshd cmsSshd) {
+ this.cmsSshd = cmsSshd;
}
}