X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2Finternal%2Fkernel%2FDeployConfig.java;h=f481f3fa10e2ce9bf1ef9838b42dbc37fecf8f18;hb=9ec85110269f8be5c83ea26e283359bb451a67b7;hp=61e840e3226d1c5c513585a41b1f2ba49915edea;hpb=0243aa5633af84d8608ba912483dbaaaefac42f1;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java index 61e840e32..f481f3fa1 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java @@ -5,12 +5,14 @@ import java.io.InputStream; import java.io.Writer; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Dictionary; import java.util.List; import java.util.SortedMap; import java.util.TreeMap; import javax.naming.InvalidNameException; +import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttributes; import javax.naming.ldap.LdapName; @@ -18,11 +20,12 @@ import javax.naming.ldap.Rdn; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.argeo.cms.CmsException; +import org.argeo.api.NodeConstants; import org.argeo.naming.AttributesDictionary; import org.argeo.naming.LdifParser; import org.argeo.naming.LdifWriter; -import org.argeo.node.NodeConstants; +import org.argeo.osgi.useradmin.UserAdminConf; +import org.eclipse.equinox.http.jetty.JettyConfigurator; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.osgi.service.cm.Configuration; @@ -30,73 +33,181 @@ import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.cm.ConfigurationEvent; import org.osgi.service.cm.ConfigurationListener; +/** Manages the LDIF-based deployment configuration. */ class DeployConfig implements ConfigurationListener { private final Log log = LogFactory.getLog(getClass()); private final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext(); - private Path deployConfigPath = KernelUtils.getOsgiInstancePath(KernelConstants.DEPLOY_CONFIG_PATH); + private static Path deployConfigPath = KernelUtils.getOsgiInstancePath(KernelConstants.DEPLOY_CONFIG_PATH); private SortedMap deployConfigs = new TreeMap<>(); + private final DataModels dataModels; - public DeployConfig(ConfigurationAdmin configurationAdmin,boolean isClean) { + private boolean isFirstInit = false; + + private final static String ROLES = "roles"; + + public DeployConfig(ConfigurationAdmin configurationAdmin, DataModels dataModels, boolean isClean) { + this.dataModels = dataModels; // ConfigurationAdmin configurationAdmin = // bc.getService(bc.getServiceReference(ConfigurationAdmin.class)); try { - if (!Files.exists(deployConfigPath)) { // first init + if (!isInitialized()) { // first init + isFirstInit = true; firstInit(); } - init(configurationAdmin, isClean); + init(configurationAdmin, isClean, isFirstInit); } catch (IOException e) { - throw new CmsException("Could not init deploy configs", e); + throw new RuntimeException("Could not init deploy configs", e); } // FIXME check race conditions during initialization // bc.registerService(ConfigurationListener.class, this, null); } private void firstInit() throws IOException { + log.info("## FIRST INIT ##"); Files.createDirectories(deployConfigPath.getParent()); - FirstInitProperties firstInit = new FirstInitProperties(); - firstInit.prepareInstanceArea(); - - if (!Files.exists(deployConfigPath))// could have juste been copied - Files.createFile(deployConfigPath); + // FirstInit firstInit = new FirstInit(); + InitUtils.prepareFirstInitInstanceArea(); - try (InputStream in = Files.newInputStream(deployConfigPath)) { - deployConfigs = new LdifParser().read(in); - } + if (!Files.exists(deployConfigPath)) + deployConfigs = new TreeMap<>(); + else// config file could have juste been copied by preparation + try (InputStream in = Files.newInputStream(deployConfigPath)) { + deployConfigs = new LdifParser().read(in); + } + save(); + } + private void setFromFrameworkProperties(boolean isFirstInit) { // node repository - Dictionary nodeConfig = firstInit + Dictionary nodeConfig = InitUtils .getNodeRepositoryConfig(getProps(NodeConstants.NODE_REPOS_FACTORY_PID, NodeConstants.NODE)); // node repository is mandatory putFactoryDeployConfig(NodeConstants.NODE_REPOS_FACTORY_PID, nodeConfig); - // user admin + // additional repositories + dataModels: for (DataModels.DataModel dataModel : dataModels.getNonAbstractDataModels()) { + if (NodeConstants.NODE_REPOSITORY.equals(dataModel.getName())) + continue dataModels; + Dictionary config = InitUtils.getRepositoryConfig(dataModel.getName(), + getProps(NodeConstants.NODE_REPOS_FACTORY_PID, dataModel.getName())); + if (config.size() != 0) + putFactoryDeployConfig(NodeConstants.NODE_REPOS_FACTORY_PID, config); + } - List> userDirectoryConfigs = firstInit.getUserDirectoryConfigs(); - for (int i = 0; i < userDirectoryConfigs.size(); i++) { - Dictionary userDirectoryConfig = userDirectoryConfigs.get(i); - String cn = Integer.toString(i); - userDirectoryConfig.put(NodeConstants.CN, cn); - putFactoryDeployConfig(NodeConstants.NODE_USER_ADMIN_PID, userDirectoryConfig); + // user admin + List> userDirectoryConfigs = InitUtils.getUserDirectoryConfigs(); + if (userDirectoryConfigs.size() != 0) { + List activeCns = new ArrayList<>(); + for (int i = 0; i < userDirectoryConfigs.size(); i++) { + Dictionary userDirectoryConfig = userDirectoryConfigs.get(i); + String baseDn = (String) userDirectoryConfig.get(UserAdminConf.baseDn.name()); + String cn; + if (NodeConstants.ROLES_BASEDN.equals(baseDn)) + cn = ROLES; + else + cn = UserAdminConf.baseDnHash(userDirectoryConfig); + activeCns.add(cn); + userDirectoryConfig.put(NodeConstants.CN, cn); + putFactoryDeployConfig(NodeConstants.NODE_USER_ADMIN_PID, userDirectoryConfig); + } + // disable others + LdapName userAdminFactoryName = serviceFactoryDn(NodeConstants.NODE_USER_ADMIN_PID); + for (LdapName name : deployConfigs.keySet()) { + if (name.startsWith(userAdminFactoryName) && !name.equals(userAdminFactoryName)) { +// try { + Attributes attrs = deployConfigs.get(name); + String cn = name.getRdn(name.size() - 1).getValue().toString(); + if (!activeCns.contains(cn)) { + attrs.put(UserAdminConf.disabled.name(), "true"); + } +// } catch (Exception e) { +// throw new CmsException("Cannot disable user directory " + name, e); +// } + } + } } // http server - Dictionary webServerConfig = firstInit - .getHttpServerConfig(getProps(KernelConstants.JETTY_FACTORY_PID, NodeConstants.DEFAULT)); - if (!webServerConfig.isEmpty()) - putFactoryDeployConfig(KernelConstants.JETTY_FACTORY_PID, webServerConfig); +// Dictionary webServerConfig = InitUtils +// .getHttpServerConfig(getProps(KernelConstants.JETTY_FACTORY_PID, NodeConstants.DEFAULT)); +// if (!webServerConfig.isEmpty()) { +// // TODO check for other customizers +// webServerConfig.put("customizer.class", "org.argeo.equinox.jetty.CmsJettyCustomizer"); +// putFactoryDeployConfig(KernelConstants.JETTY_FACTORY_PID, webServerConfig); +// } + LdapName defaultHttpServiceDn = serviceDn(KernelConstants.JETTY_FACTORY_PID, NodeConstants.DEFAULT); + if (deployConfigs.containsKey(defaultHttpServiceDn)) { + // remove old default configs since we have now to start Jetty servlet bridge + // indirectly + deployConfigs.remove(defaultHttpServiceDn); + } + // SAVE save(); + // + + // Explicitly configures Jetty so that the default server is not started by the + // activator of the Equinox Jetty bundle. + Dictionary webServerConfig = InitUtils + .getHttpServerConfig(getProps(KernelConstants.JETTY_FACTORY_PID, NodeConstants.DEFAULT)); +// if (!webServerConfig.isEmpty()) { +// webServerConfig.put("customizer.class", KernelConstants.CMS_JETTY_CUSTOMIZER_CLASS); +// +// // TODO centralise with Jetty extender +// Object webSocketEnabled = webServerConfig.get(InternalHttpConstants.WEBSOCKET_ENABLED); +// if (webSocketEnabled != null && webSocketEnabled.toString().equals("true")) { +// bc.registerService(ServerEndpointConfig.Configurator.class, new CmsWebSocketConfigurator(), null); +// webServerConfig.put(InternalHttpConstants.WEBSOCKET_ENABLED, "true"); +// } +// } + + int tryCount = 60; + try { + tryGettyJetty: while (tryCount > 0) { + try { + JettyConfigurator.startServer(KernelConstants.DEFAULT_JETTY_SERVER, webServerConfig); + // Explicitly starts Jetty OSGi HTTP bundle, so that it gets triggered if OSGi + // configuration is not cleaned + FrameworkUtil.getBundle(JettyConfigurator.class).start(); + break tryGettyJetty; + } catch (IllegalStateException e) { + // Jetty may not be ready + try { + Thread.sleep(1000); + } catch (Exception e1) { + // silent + } + tryCount--; + } + } + } catch (Exception e) { + log.error("Cannot start default Jetty server with config " + webServerConfig, e); + } + } - private void init(ConfigurationAdmin configurationAdmin, boolean isClean) throws IOException { + private void init(ConfigurationAdmin configurationAdmin, boolean isClean, boolean isFirstInit) throws IOException { try (InputStream in = Files.newInputStream(deployConfigPath)) { deployConfigs = new LdifParser().read(in); } if (isClean) { - for (LdapName dn : deployConfigs.keySet()) { + if (log.isDebugEnabled()) + log.debug("Clean state, loading from framework properties..."); + setFromFrameworkProperties(isFirstInit); + + // FIXME make it more robust + Configuration systemRolesConf = null; + LdapName systemRolesDn; + try { + // FIXME make it more robust + systemRolesDn = new LdapName("cn=roles,ou=org.argeo.api.userAdmin,ou=deploy,ou=node"); + } catch (InvalidNameException e) { + throw new IllegalArgumentException(e); + } + deployConfigs: for (LdapName dn : deployConfigs.keySet()) { Rdn lastRdn = dn.getRdn(dn.size() - 1); LdapName prefix = (LdapName) dn.getPrefix(dn.size() - 1); if (prefix.toString().equals(NodeConstants.DEPLOY_BASEDN)) { @@ -110,15 +221,28 @@ class DeployConfig implements ConfigurationListener { // service factory definition } } else { + Attributes config = deployConfigs.get(dn); + Attribute disabled = config.get(UserAdminConf.disabled.name()); + if (disabled != null) + continue deployConfigs; // service factory service Rdn beforeLastRdn = dn.getRdn(dn.size() - 2); assert beforeLastRdn.getType().equals(NodeConstants.OU); String factoryPid = beforeLastRdn.getValue().toString(); Configuration conf = configurationAdmin.createFactoryConfiguration(factoryPid.toString(), null); - AttributesDictionary dico = new AttributesDictionary(deployConfigs.get(dn)); - conf.update(dico); + if (systemRolesDn.equals(dn)) { + systemRolesConf = configurationAdmin.createFactoryConfiguration(factoryPid.toString(), null); + } else { + AttributesDictionary dico = new AttributesDictionary(config); + conf.update(dico); + } } } + + // system roles must be last since it triggers node user admin publication + if (systemRolesConf == null) + throw new IllegalStateException("System roles are not configured."); + systemRolesConf.update(new AttributesDictionary(deployConfigs.get(systemRolesDn))); } // TODO check consistency if not clean } @@ -206,10 +330,15 @@ class DeployConfig implements ConfigurationListener { try (Writer writer = Files.newBufferedWriter(deployConfigPath)) { new LdifWriter(writer).write(deployConfigs); } catch (IOException e) { - throw new CmsException("Cannot save deploy configs", e); + // throw new CmsException("Cannot save deploy configs", e); + log.error("Cannot save deploy configs", e); } } + boolean isStandalone(String dataModelName) { + return getProps(NodeConstants.NODE_REPOS_FACTORY_PID, dataModelName) != null; + } + /* * UTILITIES */ @@ -245,4 +374,12 @@ class DeployConfig implements ConfigurationListener { return null; } + private static boolean isInitialized() { + return Files.exists(deployConfigPath); + } + + public boolean isFirstInit() { + return isFirstInit; + } + }