BUNDLES = \
org.argeo.app.api \
org.argeo.app.core \
+org.argeo.app.jcr \
org.argeo.app.servlet.odk \
org.argeo.app.servlet.publish \
org.argeo.app.theme.default \
org.argeo.app.profile.acr.jcr \
swt/org.argeo.app.swt \
swt/org.argeo.app.ui \
+org.argeo.product.knowledge \
DEP_CATEGORIES = \
org.argeo.tp \
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.argeo.internal.app.core.appUserState">
- <implementation class="org.argeo.internal.app.core.AppUserStateImpl"/>
- <service>
- <provide interface="org.argeo.app.api.AppUserState"/>
- </service>
- <reference bind="setJcrContentProvider" cardinality="1..1" interface="org.argeo.cms.jcr.acr.JcrContentProvider" name="JcrContentProvider" policy="static"/>
-</scr:component>
locations=locations
recentItems=recent items
-appTitle=Argeo Suite
-
#
# PEOPLE
# org.argeo.people.ui.PeopleMsg
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" immediate="true" name="Suite Maintenance Service">
- <implementation class="org.argeo.app.core.SuiteMaintenanceService"/>
- <reference bind="setRepository" cardinality="1..1" interface="javax.jcr.Repository" name="Repository" policy="static" target="(cn=ego)"/>
- <reference bind="setUserTransaction" cardinality="1..1" interface="org.argeo.api.cms.transaction.WorkTransaction" name="WorkTransaction" policy="static"/>
- <reference bind="setUserAdmin" cardinality="1..1" interface="org.osgi.service.useradmin.UserAdmin" name="UserAdmin" policy="static"/>
- <reference bind="setContentRepository" cardinality="1..1" interface="org.argeo.api.acr.spi.ProvidedRepository" name="ContentRepository" policy="static"/>
-</scr:component>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="start" deactivate="stop" name="org.argeo.app.core.suiteMaintenance">
+ <implementation class="org.argeo.app.core.SuiteMaintenance"/>
+ <reference bind="setContentRepository" cardinality="1..1" interface="org.argeo.api.acr.spi.ProvidedRepository" name="ContentRepository" policy="static"/>
+</scr:component>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" immediate="true" name="Suite Terms Manager">
- <implementation class="org.argeo.app.core.SuiteTermsManager"/>
- <reference bind="setRepository" cardinality="1..1" interface="javax.jcr.Repository" name="Repository" policy="static" target="(cn=ego)"/>
- <service>
- <provide interface="org.argeo.app.api.TermsManager"/>
- </service>
-</scr:component>
Bundle-ActivationPolicy: lazy
Service-Component:\
-OSGI-INF/termsManager.xml,\
-OSGI-INF/maintenanceService.xml,\
-OSGI-INF/appUserState.xml,\
+OSGI-INF/suiteMaintenance.xml,\
Import-Package:\
tech.units.indriya.unit,\
org.osgi.service.useradmin,\
-javax.jcr.nodetype,\
-javax.jcr.security,\
com.fasterxml.jackson.core,\
-org.apache.jackrabbit.*;version="[1,4)",\
org.argeo.cms.acr,\
*
bin.includes = META-INF/,\
.,\
OSGI-INF/,\
- OSGI-INF/appUserState.xml
+ OSGI-INF/appUserState.xml,\
+ OSGI-INF/suiteMaintenance.xml
additional.bundles = org.argeo.init
source.. = src/
output.. = bin/
+++ /dev/null
-package org.argeo.app.core;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.ImportUUIDBehavior;
-import javax.jcr.ItemExistsException;
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.app.api.EntityType;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.maintenance.AbstractMaintenanceService;
-
-/** Base for custom initialisations. */
-public abstract class CustomMaintenanceService extends AbstractMaintenanceService {
- private final static CmsLog log = CmsLog.getLog(AbstractMaintenanceService.class);
-
- protected List<String> getTypologies() {
- return new ArrayList<>();
- }
-
- protected String getTypologiesLoadBase() {
- return "";
- }
-
- protected void loadTypologies(Node customBaseNode) throws RepositoryException, IOException {
- List<String> typologies = getTypologies();
- if (!typologies.isEmpty()) {
- Node termsBase = JcrUtils.getOrAdd(customBaseNode, EntityType.terms.name(), EntityType.typologies.get());
- for (String terms : typologies) {
- loadTerms(termsBase, terms);
- }
- // TODO do not save here, so that upper layers can decide when to save
- termsBase.getSession().save();
- }
- }
-
- protected void loadTerms(Node termsBase, String name) throws IOException, RepositoryException {
- try {
-// if (termsBase.hasNode(name))
-// return;
- String typologiesLoadBase = getTypologiesLoadBase();
- if (typologiesLoadBase.contains("/") && !typologiesLoadBase.endsWith("/"))
- typologiesLoadBase = typologiesLoadBase + "/";
- String termsLoadPath = typologiesLoadBase + name + ".xml";
- URL termsUrl = getClass().getResource(termsLoadPath);
- if (termsUrl == null)
- throw new IllegalArgumentException("Terms '" + name + "' not found.");
- try (InputStream in = termsUrl.openStream()) {
- termsBase.getSession().importXML(termsBase.getPath(), in,
- ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
- } catch (ItemExistsException e) {
- log.warn("Terms " + name + " exists with another UUID, removing it...");
- termsBase.getNode(name).remove();
- try (InputStream in = termsUrl.openStream()) {
- termsBase.getSession().importXML(termsBase.getPath(), in,
- ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
- }
- }
- if (log.isDebugEnabled())
- log.debug("Terms '" + name + "' loaded.");
- // TODO do not save here, so that upper layers can decide when to save
- termsBase.getSession().save();
- } catch (RepositoryException | IOException e) {
- log.error("Cannot load terms '" + name + "': " + e.getMessage());
- throw e;
- }
- }
-
-}
+++ /dev/null
-package org.argeo.app.core;
-
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.argeo.app.api.EntityConstants;
-import org.argeo.app.api.EntityDefinition;
-import org.argeo.cms.jcr.CmsJcrUtils;
-import org.argeo.jcr.Jcr;
-import org.osgi.framework.BundleContext;
-
-/** An entity definition based on a JCR data structure. */
-public class JcrEntityDefinition implements EntityDefinition {
- private Repository repository;
-
- private String type;
- private String defaultEditorId;
-
- public void init(BundleContext bundleContext, Map<String, String> properties) throws RepositoryException {
- Session adminSession = CmsJcrUtils.openDataAdminSession(repository, null);
- try {
- type = properties.get(EntityConstants.TYPE);
- if (type == null)
- throw new IllegalArgumentException("Entity type property " + EntityConstants.TYPE + " must be set.");
- defaultEditorId = properties.get(EntityConstants.DEFAULT_EDITOR_ID);
-// String definitionPath = EntityNames.ENTITY_DEFINITIONS_PATH + '/' + type;
-// if (!adminSession.itemExists(definitionPath)) {
-// Node entityDefinition = JcrUtils.mkdirs(adminSession, definitionPath, EntityTypes.ENTITY_DEFINITION);
-//// entityDefinition.addMixin(EntityTypes.ENTITY_DEFINITION);
-// adminSession.save();
-// }
- initJcr(adminSession);
- } finally {
- Jcr.logout(adminSession);
- }
- }
-
- /** To be overridden in order to perform additional initialisations. */
- protected void initJcr(Session adminSession) throws RepositoryException {
-
- }
-
- public void destroy(BundleContext bundleContext, Map<String, String> properties) throws RepositoryException {
-
- }
-
- @Override
- public String getEditorId(Node entity) {
- return defaultEditorId;
- }
-
- @Override
- public String getType() {
- return type;
- }
-
- protected Repository getRepository() {
- return repository;
- }
-
- public void setRepository(Repository repository) {
- this.repository = repository;
- }
-
- public String toString() {
- return "Entity Definition " + getType();
- }
-
-}
--- /dev/null
+package org.argeo.app.core;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.measure.Quantity;
+import javax.measure.quantity.Area;
+
+import org.argeo.api.acr.spi.ContentNamespace;
+import org.argeo.api.acr.spi.ProvidedRepository;
+import org.geotools.gml3.v3_2.GML;
+
+import si.uom.SI;
+import tech.units.indriya.quantity.Quantities;
+
+/**
+ * Background service starting and stopping with the whole system, and making
+ * sure it is in a proper state.
+ */
+public class SuiteMaintenance {
+ private ProvidedRepository contentRepository;
+
+ public void start() {
+ // make sure that the unit system is initialised
+ Quantity<Area> dummy = Quantities.getQuantity(0, SI.SQUARE_METRE);
+
+ getContentRepository().registerTypes(SuiteContentNamespace.values());
+// for (SuiteContentTypes types : SuiteContentTypes.values()) {
+// getContentRepository().registerTypes(types.getDefaultPrefix(), types.getNamespace(),
+// types.getResource() != null ? types.getResource().toExternalForm() : null);
+// }
+
+ // GML schema import fails because of xlinks issues
+ getContentRepository().registerTypes(new ContentNamespace() {
+
+ @Override
+ public URL getSchemaResource() {
+ try {
+ return new URL(GML.getInstance().getSchemaLocation());
+ } catch (MalformedURLException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ @Override
+ public String getNamespaceURI() {
+ return GML.getInstance().getNamespaceURI();
+ }
+
+ @Override
+ public String getDefaultPrefix() {
+ return "gml";
+ }
+ });
+
+ }
+
+ public void stop() {
+
+ }
+
+ protected ProvidedRepository getContentRepository() {
+ return contentRepository;
+ }
+
+ public void setContentRepository(ProvidedRepository contentRepository) {
+ this.contentRepository = contentRepository;
+ }
+
+}
+++ /dev/null
-package org.argeo.app.core;
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.security.Privilege;
-import javax.measure.Quantity;
-import javax.measure.quantity.Area;
-
-import org.argeo.api.acr.spi.ContentNamespace;
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.app.api.EntityType;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.maintenance.AbstractMaintenanceService;
-import org.geotools.gml3.v3_2.GML;
-
-import si.uom.SI;
-import tech.units.indriya.quantity.Quantities;
-
-/** Initialises an Argeo Suite backend. */
-public class SuiteMaintenanceService extends AbstractMaintenanceService {
- @Override
- public void init() {
- // make sure that the unit system is initialised
- Quantity<Area> dummy = Quantities.getQuantity(0, SI.SQUARE_METRE);
-
- super.init();
-
- getContentRepository().registerTypes(SuiteContentNamespace.values());
-// for (SuiteContentTypes types : SuiteContentTypes.values()) {
-// getContentRepository().registerTypes(types.getDefaultPrefix(), types.getNamespace(),
-// types.getResource() != null ? types.getResource().toExternalForm() : null);
-// }
-
- // GML schema import fails because of xlinks issues
- getContentRepository().registerTypes(new ContentNamespace() {
-
- @Override
- public URL getSchemaResource() {
- try {
- return new URL(GML.getInstance().getSchemaLocation());
- } catch (MalformedURLException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
- @Override
- public String getNamespaceURI() {
- return GML.getInstance().getNamespaceURI();
- }
-
- @Override
- public String getDefaultPrefix() {
- return "gml";
- }
- });
- }
-
- @Override
- public boolean prepareJcrTree(Session adminSession) throws RepositoryException, IOException {
- boolean modified = false;
- Node rootNode = adminSession.getRootNode();
- if (!rootNode.hasNode(EntityType.user.name())) {
- rootNode.addNode(EntityType.user.name(), NodeType.NT_UNSTRUCTURED);
- modified = true;
- }
- if (modified)
- adminSession.save();
- return modified;
- }
-
- @Override
- public void configurePrivileges(Session adminSession) throws RepositoryException {
- JcrUtils.addPrivilege(adminSession, EntityType.user.basePath(), CmsConstants.ROLE_USER_ADMIN,
- Privilege.JCR_ALL);
- // JcrUtils.addPrivilege(adminSession, "/", SuiteRole.coworker.dn(),
- // Privilege.JCR_READ);
- }
-
-}
+++ /dev/null
-package org.argeo.app.core;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.argeo.app.api.Term;
-
-/**
- * A single term. Helper to optimise {@link SuiteTermsManager} implementation.
- */
-class SuiteTerm implements Term {
- private final String name;
- private final String relativePath;
- private final SuiteTypology typology;
- private final String id;
-
- private final SuiteTerm parentTerm;
- private final List<SuiteTerm> subTerms = new ArrayList<>();
-
- SuiteTerm(SuiteTypology typology, String relativePath, SuiteTerm parentTerm) {
- this.typology = typology;
- this.parentTerm = parentTerm;
- this.relativePath = relativePath;
- int index = relativePath.lastIndexOf('/');
- if (index > 0) {
- this.name = relativePath.substring(index + 1);
- } else {
- this.name = relativePath;
- }
- id = typology.getName() + '/' + relativePath;
- }
-
- @Override
- public String getId() {
- return id;
- }
-
- @Override
- public String getName() {
- return name;
- }
-
- public String getRelativePath() {
- return relativePath;
- }
-
- @Override
- public SuiteTypology getTypology() {
- return typology;
- }
-
- @Override
- public List<SuiteTerm> getSubTerms() {
- return subTerms;
- }
-
- @Override
- public SuiteTerm getParentTerm() {
- return parentTerm;
- }
-
-}
+++ /dev/null
-package org.argeo.app.core;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.app.api.EntityNames;
-import org.argeo.app.api.EntityType;
-import org.argeo.app.api.Term;
-import org.argeo.app.api.TermsManager;
-import org.argeo.cms.jcr.CmsJcrUtils;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrException;
-
-/** Argeo Suite implementation of terms manager. */
-public class SuiteTermsManager implements TermsManager {
- private final Map<String, SuiteTerm> terms = new HashMap<>();
- private final Map<String, SuiteTypology> typologies = new HashMap<>();
-
- // JCR
- private Repository repository;
- private Session adminSession;
-
- public void init() {
- adminSession = CmsJcrUtils.openDataAdminSession(repository, CmsConstants.SYS_WORKSPACE);
- }
-
- @Override
- public List<Term> listAllTerms(String typology) {
- List<Term> res = new ArrayList<>();
- SuiteTypology t = getTypology(typology);
- for (SuiteTerm term : t.getAllTerms()) {
- res.add(term);
- }
- return res;
- }
-
- @Override
- public SuiteTerm getTerm(String termId) {
- return terms.get(termId);
- }
-
- @Override
- public SuiteTypology getTypology(String typology) {
- SuiteTypology t = typologies.get(typology);
- if (t == null) {
- Node termsNode = Jcr.getNode(adminSession, "SELECT * FROM [{0}] WHERE NAME()=\"{1}\"",
- EntityType.terms.get(), typology);
- if (termsNode == null)
- throw new IllegalArgumentException("Typology " + typology + " not found.");
- t = loadTypology(termsNode);
- }
- return t;
- }
-
- SuiteTypology loadTypology(Node termsNode) {
- try {
- SuiteTypology typology = new SuiteTypology(termsNode);
- for (Node termNode : Jcr.iterate(termsNode.getNodes())) {
- if (termNode.isNodeType(EntityType.term.get())) {
- SuiteTerm term = loadTerm(typology, termNode, null);
- if (!term.getSubTerms().isEmpty())
- typology.markNotFlat();
- typology.getSubTerms().add(term);
- }
- }
- typologies.put(typology.getName(), typology);
- return typology;
- } catch (RepositoryException e) {
- throw new JcrException("Cannot load typology from " + termsNode, e);
- }
- }
-
- SuiteTerm loadTerm(SuiteTypology typology, Node termNode, SuiteTerm parentTerm) throws RepositoryException {
- String name = termNode.getProperty(EntityNames.NAME).getString();
- String relativePath = parentTerm == null ? name : parentTerm.getRelativePath() + '/' + name;
- SuiteTerm term = new SuiteTerm(typology, relativePath, parentTerm);
- terms.put(term.getId(), term);
- for (Node subTermNode : Jcr.iterate(termNode.getNodes())) {
- if (termNode.isNodeType(EntityType.term.get())) {
- SuiteTerm subTerm = loadTerm(typology, subTermNode, term);
- term.getSubTerms().add(subTerm);
- }
- }
- return term;
- }
-
- public void destroy() {
- Jcr.logout(adminSession);
- }
-
- public void setRepository(Repository repository) {
- this.repository = repository;
- }
-
-}
+++ /dev/null
-package org.argeo.app.core;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.Node;
-
-import org.argeo.app.api.Term;
-import org.argeo.app.api.Typology;
-import org.argeo.jcr.Jcr;
-
-/** A typology. Helper to optimise {@link SuiteTermsManager} implementation. */
-class SuiteTypology implements Typology {
- private final String name;
- private final Node node;
- private boolean isFlat = true;
-
- private final List<SuiteTerm> subTerms = new ArrayList<>();
-
- public SuiteTypology(Node node) {
- this.node = node;
- this.name = Jcr.getName(this.node);
- }
-
- @Override
- public String getId() {
- return name;
- }
-
- public String getName() {
- return name;
- }
-
- public Node getNode() {
- return node;
- }
-
- void markNotFlat() {
- if (isFlat)
- isFlat = false;
- }
-
- @Override
- public boolean isFlat() {
- return isFlat;
- }
-
- @Override
- public List<SuiteTerm> getSubTerms() {
- return subTerms;
- }
-
- public List<SuiteTerm> getAllTerms() {
- if (isFlat)
- return subTerms;
- else {
- List<SuiteTerm> terms = new ArrayList<>();
- for (SuiteTerm subTerm : subTerms) {
- terms.add(subTerm);
- collectSubTerms(terms, subTerm);
- }
- return terms;
- }
- }
-
- public Term findTermByName(String name) {
- List<SuiteTerm> collected = new ArrayList<>();
- for (SuiteTerm subTerm : subTerms) {
- collectTermsByName(subTerm, name, collected);
- }
- if (collected.isEmpty())
- return null;
- if (collected.size() == 1)
- return collected.get(0);
- throw new IllegalArgumentException(
- "There are " + collected.size() + " terms with name " + name + " in typology " + getId());
- }
-
- private void collectTermsByName(SuiteTerm term, String name, List<SuiteTerm> collected) {
- if (term.getName().equals(name)) {
- collected.add(term);
- }
- for (SuiteTerm subTerm : term.getSubTerms()) {
- collectTermsByName(subTerm, name, collected);
- }
- }
-
- private void collectSubTerms(List<SuiteTerm> terms, SuiteTerm term) {
- for (SuiteTerm subTerm : term.getSubTerms()) {
- terms.add(subTerm);
- collectSubTerms(terms, subTerm);
- }
- }
-
-}
import java.util.HashSet;
import java.util.Set;
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.security.Privilege;
-import javax.security.auth.x500.X500Principal;
import javax.xml.namespace.QName;
import org.argeo.api.acr.Content;
import org.argeo.api.acr.ldap.LdapAttr;
import org.argeo.api.acr.ldap.LdapObj;
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.api.cms.CmsSession;
import org.argeo.app.api.EntityType;
import org.argeo.cms.RoleNameUtils;
-import org.argeo.jcr.JcrException;
-import org.argeo.jcr.JcrUtils;
/** Utilities around the Argeo Suite APIs. */
public class SuiteUtils {
return EntityType.user.basePath() + '/' + uid;
}
- public static Node getOrCreateUserNode(Session adminSession, String userDn) {
- try {
- Node usersBase = adminSession.getNode(EntityType.user.basePath());
- String uid = RoleNameUtils.getLastRdnValue(userDn);
- Node userNode;
- if (!usersBase.hasNode(uid)) {
- userNode = usersBase.addNode(uid, NodeType.NT_UNSTRUCTURED);
- userNode.addMixin(EntityType.user.get());
- userNode.addMixin(NodeType.MIX_CREATED);
- userNode.setProperty(LdapAttr.distinguishedName.get(), userDn.toString());
- userNode.setProperty(LdapAttr.uid.get(), uid);
- } else {
- userNode = usersBase.getNode(uid);
- }
-
- if (!userNode.hasNode(USER_SESSIONS_NODE_NAME)) {
- // Migrate existing user node
- Node sessionsNode = userNode.addNode(USER_SESSIONS_NODE_NAME, NodeType.NT_UNSTRUCTURED);
- oldSessions: for (NodeIterator nit = userNode.getNodes(); nit.hasNext();) {
- Node child = nit.nextNode();
- if (USER_SESSIONS_NODE_NAME.equals(child.getName()) || child.getName().startsWith("rep:")
- || child.getName().startsWith("jcr:"))
- continue oldSessions;
- Node target = sessionsNode.addNode(child.getName());
- JcrUtils.copy(child, target);
- }
-
- Node userStateNode = userNode.addNode(USER_STATE_NODE_NAME, NodeType.NT_UNSTRUCTURED);
- Node userDevicesNode = userNode.addNode(USER_DEVICES_NODE_NAME, NodeType.NT_UNSTRUCTURED);
-
- adminSession.save();
-// JackrabbitSecurityUtils.denyPrivilege(adminSession, userNode.getPath(), SuiteRole.coworker.dn(),
-// Privilege.JCR_READ);
- JcrUtils.addPrivilege(adminSession, userNode.getPath(), new X500Principal(userDn.toString()).getName(),
- Privilege.JCR_READ);
- JcrUtils.addPrivilege(adminSession, userNode.getPath(), CmsConstants.ROLE_USER_ADMIN,
- Privilege.JCR_ALL);
-
- JcrUtils.addPrivilege(adminSession, userStateNode.getPath(), userDn, Privilege.JCR_ALL);
- JcrUtils.addPrivilege(adminSession, userDevicesNode.getPath(), userDn, Privilege.JCR_ALL);
- }
- return userNode;
- } catch (RepositoryException e) {
- throw new JcrException("Cannot create user node for " + userDn, e);
- }
- }
-
- public static Node getCmsSessionNode(Session session, CmsSession cmsSession) {
- try {
- return session.getNode(getUserNodePath(cmsSession.getUserDn()) + '/' + USER_SESSIONS_NODE_NAME + '/'
- + cmsSession.getUuid().toString());
- } catch (RepositoryException e) {
- throw new JcrException("Cannot get session dir for " + cmsSession, e);
- }
- }
-
- public static Node getOrCreateCmsSessionNode(Session adminSession, CmsSession cmsSession) {
- try {
- String userDn = cmsSession.getUserDn();
- Node userNode = getOrCreateUserNode(adminSession, userDn);
- Node sessionsNode = userNode.getNode(USER_SESSIONS_NODE_NAME);
- String cmsSessionUuid = cmsSession.getUuid().toString();
- Node cmsSessionNode;
- if (!sessionsNode.hasNode(cmsSessionUuid)) {
- cmsSessionNode = sessionsNode.addNode(cmsSessionUuid, NodeType.NT_UNSTRUCTURED);
- cmsSessionNode.addMixin(NodeType.MIX_CREATED);
- adminSession.save();
- JcrUtils.addPrivilege(adminSession, cmsSessionNode.getPath(), cmsSession.getUserRole(),
- Privilege.JCR_ALL);
- } else {
- cmsSessionNode = sessionsNode.getNode(cmsSessionUuid);
- }
- return cmsSessionNode;
- } catch (RepositoryException e) {
- throw new JcrException("Cannot create session dir for " + cmsSession, e);
- }
- }
-
public static Set<String> extractRoles(String[] semiColArr) {
Set<String> res = new HashSet<>();
// TODO factorize and make it more robust
+++ /dev/null
-package org.argeo.app.core;
-
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryManager;
-
-import org.apache.jackrabbit.util.ISO9075;
-import org.argeo.api.cms.CmsLog;
-
-/** Ease XPath generation for JCR requests */
-public class XPathUtils {
- private final static CmsLog log = CmsLog.getLog(XPathUtils.class);
-
- private final static String QUERY_XPATH = "xpath";
-
- public static String descendantFrom(String parentPath) {
- if (notEmpty(parentPath)) {
- if ("/".equals(parentPath))
- parentPath = "";
- // Hardcoded dependency to Jackrabbit. Remove
- String result = "/jcr:root" + ISO9075.encodePath(parentPath);
- if (log.isTraceEnabled()) {
- String result2 = "/jcr:root" + parentPath;
- if (!result2.equals(result))
- log.warn("Encoded Path " + result2 + " --> " + result);
- }
- return result;
- } else
- return "";
- }
-
- public static String localAnd(String... conditions) {
- StringBuilder builder = new StringBuilder();
- for (String condition : conditions) {
- if (notEmpty(condition)) {
- builder.append(" ").append(condition).append(" and ");
- }
- }
- if (builder.length() > 3)
- return builder.substring(0, builder.length() - 4);
- else
- return "";
- }
-
- public static String xPathNot(String condition) {
- if (notEmpty(condition))
- return "not(" + condition + ")";
- else
- return "";
- }
-
- public static String getFreeTextConstraint(String filter) throws RepositoryException {
- StringBuilder builder = new StringBuilder();
- if (notEmpty(filter)) {
- String[] strs = filter.trim().split(" ");
- for (String token : strs) {
- builder.append("jcr:contains(.,'*" + encodeXPathStringValue(token) + "*') and ");
- }
- return builder.substring(0, builder.length() - 4);
- }
- return "";
- }
-
- public static String getPropertyContains(String propertyName, String filter) throws RepositoryException {
- if (notEmpty(filter))
- return "jcr:contains(@" + propertyName + ",'*" + encodeXPathStringValue(filter) + "*')";
- return "";
- }
-
- private final static DateFormat jcrRefFormatter = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSS'+02:00'");
-
- /**
- * @param propertyName
- * @param calendar the reference date
- * @param lowerOrGreater "<", ">" TODO validate ">="
- * @throws RepositoryException
- */
- public static String getPropertyDateComparaison(String propertyName, Calendar cal, String lowerOrGreater)
- throws RepositoryException {
- if (cal != null) {
- String jcrDateStr = jcrRefFormatter.format(cal.getTime());
-
- // jcrDateStr = "2015-08-03T05:00:03:000Z";
- String result = "@" + propertyName + " " + lowerOrGreater + " xs:dateTime('" + jcrDateStr + "')";
- return result;
- }
- return "";
- }
-
- public static String getPropertyEquals(String propertyName, String value) {
- if (notEmpty(value))
- return "@" + propertyName + "='" + encodeXPathStringValue(value) + "'";
- return "";
- }
-
- public static String encodeXPathStringValue(String propertyValue) {
- // TODO implement safer mechanism to escape invalid characters
- // Also check why we have used this regex in ResourceSerrviceImpl l 474
- // String cleanedKey = key.replaceAll("(?:')", "''");
- String result = propertyValue.replaceAll("'", "''");
- return result;
- }
-
- public static void andAppend(StringBuilder builder, String condition) {
- if (notEmpty(condition)) {
- builder.append(condition);
- builder.append(" and ");
- }
- }
-
- public static void appendOrderByProperties(StringBuilder builder, boolean ascending, String... propertyNames) {
- if (propertyNames.length > 0) {
- builder.append(" order by ");
- for (String propName : propertyNames)
- builder.append("@").append(propName).append(", ");
- builder = builder.delete(builder.length() - 2, builder.length());
- if (ascending)
- builder.append(" ascending ");
- else
- builder.append(" descending ");
- }
- }
-
- public static void appendAndPropStringCondition(StringBuilder builder, String propertyName, String filter)
- throws RepositoryException {
- if (notEmpty(filter)) {
- andAppend(builder, getPropertyContains(propertyName, filter));
- }
- }
-
- public static void appendAndNotPropStringCondition(StringBuilder builder, String propertyName, String filter)
- throws RepositoryException {
- if (notEmpty(filter)) {
- String cond = getPropertyContains(propertyName, filter);
- builder.append(xPathNot(cond));
- builder.append(" and ");
- }
- }
-
- public static Query createQuery(Session session, String queryString) throws RepositoryException {
- QueryManager queryManager = session.getWorkspace().getQueryManager();
- // Localise JCR properties for XPATH
- queryString = localiseJcrItemNames(queryString);
- return queryManager.createQuery(queryString, QUERY_XPATH);
- }
-
- private final static String NS_JCR = "\\{http://www.jcp.org/jcr/1.0\\}";
- private final static String NS_NT = "\\{http://www.jcp.org/jcr/nt/1.0\\}";
- private final static String NS_MIX = "\\{http://www.jcp.org/jcr/mix/1.0\\}";
-
- /**
- * Replace the generic namespace with the local "jcr:", "nt:", "mix:" values. It
- * is a workaround that must be later cleaned
- */
- public static String localiseJcrItemNames(String name) {
- name = name.replaceAll(NS_JCR, "jcr:");
- name = name.replaceAll(NS_NT, "nt:");
- name = name.replaceAll(NS_MIX, "mix:");
- return name;
- }
-
- private static boolean notEmpty(String stringToTest) {
- return !(stringToTest == null || "".equals(stringToTest.trim()));
- }
-
- /** Singleton. */
- private XPathUtils() {
-
- }
-}
+++ /dev/null
-package org.argeo.app.docbook;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.jcr.ImportUUIDBehavior;
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.Result;
-import javax.xml.transform.Source;
-import javax.xml.transform.Templates;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-import javax.xml.transform.stream.StreamSource;
-
-import org.argeo.jcr.JcrException;
-import org.w3c.dom.Document;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-
-import net.sf.saxon.BasicTransformerFactory;
-import net.sf.saxon.TransformerFactoryImpl;
-
-/** Convert from DocBook v4 to DocBook v5, using the official XSL. */
-public class Dbk4Converter {
- private final Templates templates;
-
- public Dbk4Converter() {
- try (InputStream in = getClass().getResourceAsStream("db4-upgrade.xsl")) {
- Source xsl = new StreamSource(in);
- TransformerFactory transformerFactory = new BasicTransformerFactory();
-// TransformerFactory transformerFactory = new TransformerFactoryImpl();
- templates = transformerFactory.newTemplates(xsl);
- } catch (IOException | TransformerConfigurationException e) {
- throw new RuntimeException("Cannot initialise DocBook v4 converter", e);
- }
- }
-
- public void importXml(Node baseNode, InputStream in) throws IOException {
- try (ByteArrayOutputStream out = new ByteArrayOutputStream();) {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setXIncludeAware(true);
- factory.setNamespaceAware(true);
- DocumentBuilder docBuilder = factory.newDocumentBuilder();
- Document doc = docBuilder.parse(new InputSource(in));
- Source xmlInput = new DOMSource(doc);
-
-// ContentHandler contentHandler = baseNode.getSession().getImportContentHandler(baseNode.getPath(),
-// ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
-
- Transformer transformer = templates.newTransformer();
- Result xmlOutput = new StreamResult(out);
- transformer.transform(xmlInput, xmlOutput);
- try (InputStream dbk5in = new ByteArrayInputStream(out.toByteArray())) {
- baseNode.getSession().importXML(baseNode.getPath(), dbk5in,
- ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
- }
- } catch (RepositoryException e) {
- throw new JcrException("Cannot import XML to " + baseNode, e);
- } catch (TransformerException | SAXException | ParserConfigurationException e) {
- throw new RuntimeException("Cannot import DocBook v4 to " + baseNode, e);
- }
-
- }
-
- public static void main(String[] args) {
- try {
-
- Source xsl = new StreamSource(new File("/usr/share/xml/docbook5/stylesheet/upgrade/db4-upgrade.xsl"));
- TransformerFactory transformerFactory = new TransformerFactoryImpl();
- Templates templates = transformerFactory.newTemplates(xsl);
-
- File inputDir = new File(args[0]);
- File outputDir = new File(args[1]);
-
- for (File inputFile : inputDir.listFiles()) {
- Result xmlOutput = new StreamResult(new File(outputDir, inputFile.getName()));
-
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setXIncludeAware(true);
- factory.setNamespaceAware(true);
- DocumentBuilder docBuilder = factory.newDocumentBuilder();
- Document doc = docBuilder.parse(inputFile);
- Source xmlInput = new DOMSource(doc);
- Transformer transformer = templates.newTransformer();
- transformer.transform(xmlInput, xmlOutput);
- }
- } catch (Throwable e) {
- e.printStackTrace();
- }
- }
-
-}
+++ /dev/null
-package org.argeo.app.docbook;
-
-import static org.argeo.app.docbook.DbkType.para;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-
-import javax.jcr.ImportUUIDBehavior;
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.PathNotFoundException;
-import javax.jcr.RepositoryException;
-import javax.jcr.ValueFormatException;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.app.api.EntityType;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrException;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.jcr.JcrxApi;
-
-/** Utilities around DocBook. */
-public class DbkUtils {
- private final static CmsLog log = CmsLog.getLog(DbkUtils.class);
-
- /** Get or add a DocBook element. */
- public static Node getOrAddDbk(Node parent, DbkType child) {
- try {
- if (!parent.hasNode(child.get())) {
- return addDbk(parent, child);
- } else {
- return parent.getNode(child.get());
- }
- } catch (RepositoryException e) {
- throw new JcrException("Cannot get or add element " + child.get() + " to " + parent, e);
- }
- }
-
- /** Add a DocBook element to this node. */
- public static Node addDbk(Node parent, DbkType child) {
- try {
- Node node = parent.addNode(child.get(), child.get());
- return node;
- } catch (RepositoryException e) {
- throw new JcrException("Cannot add element " + child.get() + " to " + parent, e);
- }
- }
-
- /** Whether this DocBook element is of this type. */
- public static boolean isDbk(Node node, DbkType type) {
- return Jcr.getName(node).equals(type.get());
- }
-
- /** Whether this node is a DocBook type. */
- public static boolean isDbk(Node node) {
- String name = Jcr.getName(node);
- for (DbkType type : DbkType.values()) {
- if (name.equals(type.get()))
- return true;
- }
- return false;
- }
-
- public static String getTitle(Node node) {
- return JcrxApi.getXmlValue(node, DbkType.title.get());
- }
-
- public static void setTitle(Node node, String txt) {
- Node titleNode = getOrAddDbk(node, DbkType.title);
- JcrxApi.setXmlValue(titleNode, txt);
- }
-
- public static Node getMetadata(Node infoContainer) {
- try {
- if (!infoContainer.hasNode(DbkType.info.get()))
- return null;
- Node info = infoContainer.getNode(DbkType.info.get());
- if (!info.hasNode(EntityType.local.get()))
- return null;
- return info.getNode(EntityType.local.get());
- } catch (RepositoryException e) {
- throw new JcrException("Cannot retrieve metadata from " + infoContainer, e);
- }
- }
-
- public static Node getChildByRole(Node parent, String role) {
- try {
- NodeIterator baseSections = parent.getNodes();
- while (baseSections.hasNext()) {
- Node n = baseSections.nextNode();
- String r = Jcr.get(n, DbkAttr.role.name());
- if (r != null && r.equals(role))
- return n;
- }
- return null;
- } catch (RepositoryException e) {
- throw new JcrException("Cannot get child from " + parent + " with role " + role, e);
- }
- }
-
- public static Node addParagraph(Node node, String txt) {
- Node p = addDbk(node, para);
- JcrxApi.setXmlValue(p, txt);
- return p;
- }
-
- /**
- * Removes a paragraph if it empty. The sesison is not saved.
- *
- * @return true if the paragraph was empty and it was removed
- */
- public static boolean removeIfEmptyParagraph(Node node) {
- try {
- if (isDbk(node, DbkType.para)) {
- NodeIterator nit = node.getNodes();
- if (!nit.hasNext()) {
- node.remove();
- return true;
- }
- Node first = nit.nextNode();
- if (nit.hasNext())
- return false;
- if (first.getName().equals(Jcr.JCR_XMLTEXT)) {
- String str = Jcr.get(first, Jcr.JCR_XMLCHARACTERS);
- if (str != null && str.trim().equals("")) {
- node.remove();
- return true;
- }
- } else {
- return false;
- }
- }
- return false;
- } catch (RepositoryException e) {
- throw new JcrException("Cannot remove possibly empty paragraph", e);
- }
- }
-
- public static Node insertImageAfter(Node sibling) {
- try {
-
- Node parent = sibling.getParent();
- Node mediaNode = addDbk(parent, DbkType.mediaobject);
- // TODO optimise?
- parent.orderBefore(mediaNode.getName() + "[" + mediaNode.getIndex() + "]",
- sibling.getName() + "[" + sibling.getIndex() + "]");
- parent.orderBefore(sibling.getName() + "[" + sibling.getIndex() + "]",
- mediaNode.getName() + "[" + mediaNode.getIndex() + "]");
-
- Node imageNode = addDbk(mediaNode, DbkType.imageobject);
- Node imageDataNode = addDbk(imageNode, DbkType.imagedata);
-// Node infoNode = imageNode.addNode(DocBookTypes.INFO, DocBookTypes.INFO);
-// Node fileNode = JcrUtils.copyBytesAsFile(mediaFolder, EntityType.box.get(), new byte[0]);
-// fileNode.addMixin(EntityType.box.get());
-// fileNode.setProperty(EntityNames.SVG_WIDTH, 0);
-// fileNode.setProperty(EntityNames.SVG_LENGTH, 0);
-// fileNode.addMixin(NodeType.MIX_MIMETYPE);
-//
-// // we assume this is a folder next to the main DocBook document
-// // TODO make it more robust and generic
-// String fileRef = mediaNode.getName();
-// imageDataNode.setProperty(DocBookNames.DBK_FILEREF, fileRef);
- return mediaNode;
- } catch (RepositoryException e) {
- throw new JcrException("Cannot insert empty image after " + sibling, e);
- }
- }
-
- public static Node insertVideoAfter(Node sibling) {
- try {
-
- Node parent = sibling.getParent();
- Node mediaNode = addDbk(parent, DbkType.mediaobject);
- // TODO optimise?
- parent.orderBefore(mediaNode.getName() + "[" + mediaNode.getIndex() + "]",
- sibling.getName() + "[" + sibling.getIndex() + "]");
- parent.orderBefore(sibling.getName() + "[" + sibling.getIndex() + "]",
- mediaNode.getName() + "[" + mediaNode.getIndex() + "]");
-
- Node videoNode = addDbk(mediaNode, DbkType.videoobject);
- Node videoDataNode = addDbk(videoNode, DbkType.videodata);
- return mediaNode;
- } catch (RepositoryException e) {
- throw new JcrException("Cannot insert empty image after " + sibling, e);
- }
- }
-
- public static String getMediaFileref(Node node) {
- try {
- Node mediadata;
- if (node.hasNode(DbkType.imageobject.get())) {
- mediadata = node.getNode(DbkType.imageobject.get()).getNode(DbkType.imagedata.get());
- } else if (node.hasNode(DbkType.videoobject.get())) {
- mediadata = node.getNode(DbkType.videoobject.get()).getNode(DbkType.videodata.get());
- } else {
- throw new IllegalArgumentException("Fileref not found in " + node);
- }
-
- if (mediadata.hasProperty(DbkAttr.fileref.name())) {
- return mediadata.getProperty(DbkAttr.fileref.name()).getString();
- } else {
- return null;
- }
- } catch (RepositoryException e) {
- throw new JcrException("Cannot retrieve file ref from " + node, e);
- }
- }
-
- public static void exportXml(Node node, OutputStream out) throws IOException {
- try {
- node.getSession().exportDocumentView(node.getPath(), out, false, false);
- } catch (RepositoryException e) {
- throw new JcrException("Cannot export " + node + " to XML", e);
- }
- }
-
- public static void exportToFs(Node baseNode, DbkType type, Path directory) {
- String fileName = Jcr.getName(baseNode) + ".dbk.xml";
- Path filePath = directory.resolve(fileName);
- Node docBookNode = Jcr.getNode(baseNode, type.get());
- if (docBookNode == null)
- throw new IllegalArgumentException("No " + type.get() + " under " + baseNode);
- try {
- Files.createDirectories(directory);
- try (OutputStream out = Files.newOutputStream(filePath)) {
- exportXml(docBookNode, out);
- }
- JcrUtils.copyFilesToFs(baseNode, directory, true);
- if (log.isDebugEnabled())
- log.debug("DocBook " + baseNode + " exported to " + filePath.toAbsolutePath());
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- public static void importXml(Node baseNode, InputStream in) throws IOException {
- try {
- baseNode.getSession().importXML(baseNode.getPath(), in,
- ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
- } catch (RepositoryException e) {
- throw new JcrException("Cannot import XML to " + baseNode, e);
- }
-
- }
-
- /** Singleton. */
- private DbkUtils() {
- }
-
-}
+++ /dev/null
-<?xml version="1.0"?>
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
- xmlns:exsl="http://exslt.org/common"
- xmlns:db = "http://docbook.org/ns/docbook"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- exclude-result-prefixes="exsl db"
- version="1.0">
-
-<!--
-# ======================================================================
-# This file is part of DocBook V5.0CR5
-#
-# Copyright 2005 Norman Walsh, Sun Microsystems, Inc., and the
-# Organization for the Advancement of Structured Information
-# Standards (OASIS).
-#
-# Release: $Id: db4-upgrade.xsl 7660 2008-02-06 13:48:36Z nwalsh $
-#
-# Permission to use, copy, modify and distribute this stylesheet
-# and its accompanying documentation for any purpose and without fee
-# is hereby granted in perpetuity, provided that the above copyright
-# notice and this paragraph appear in all copies. The copyright
-# holders make no representation about the suitability of the schema
-# for any purpose. It is provided "as is" without expressed or implied
-# warranty.
-#
-# Please direct all questions, bug reports, or suggestions for changes
-# to the docbook@lists.oasis-open.org mailing list. For more
-# information, see http://www.oasis-open.org/docbook/.
-#
-# ======================================================================
--->
-
-<xsl:variable name="version" select="'1.0'"/>
-
-<xsl:output method="xml" encoding="utf-8" indent="no" omit-xml-declaration="yes"/>
-
-<xsl:preserve-space elements="*"/>
-<xsl:param name="rootid">
- <xsl:choose>
- <xsl:when test="/*/@id">
- <xsl:value-of select="/*/@id"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:text>UNKNOWN</xsl:text>
- </xsl:otherwise>
- </xsl:choose>
-</xsl:param>
-
-<xsl:param name="defaultDate" select="''"/>
-
-<xsl:template match="/">
- <xsl:variable name="converted">
- <xsl:apply-templates/>
- </xsl:variable>
- <xsl:comment>
- <xsl:text> Converted by db4-upgrade version </xsl:text>
- <xsl:value-of select="$version"/>
- <xsl:text> </xsl:text>
- </xsl:comment>
- <xsl:text> </xsl:text>
- <xsl:apply-templates select="exsl:node-set($converted)/*" mode="addNS"/>
-</xsl:template>
-
-<xsl:template match="bookinfo|chapterinfo|articleinfo|artheader|appendixinfo
- |blockinfo
- |bibliographyinfo|glossaryinfo|indexinfo|setinfo
- |setindexinfo
- |sect1info|sect2info|sect3info|sect4info|sect5info
- |sectioninfo
- |refsect1info|refsect2info|refsect3info|refsectioninfo
- |referenceinfo|partinfo"
- priority="200">
- <info>
- <xsl:call-template name="copy.attributes"/>
-
- <!-- titles can be inside or outside or both. fix that -->
- <xsl:choose>
- <xsl:when test="title and following-sibling::title">
- <xsl:if test="title != following-sibling::title">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Check </xsl:text>
- <xsl:value-of select="name(..)"/>
- <xsl:text> title.</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
- </xsl:if>
- <xsl:apply-templates select="title" mode="copy"/>
- </xsl:when>
- <xsl:when test="title">
- <xsl:apply-templates select="title" mode="copy"/>
- </xsl:when>
- <xsl:when test="following-sibling::title">
- <xsl:apply-templates select="following-sibling::title" mode="copy"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Check </xsl:text>
- <xsl:value-of select="name(..)"/>
- <xsl:text>: no title.</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
- </xsl:otherwise>
- </xsl:choose>
-
- <xsl:choose>
- <xsl:when test="titleabbrev and following-sibling::titleabbrev">
- <xsl:if test="titleabbrev != following-sibling::titleabbrev">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Check </xsl:text>
- <xsl:value-of select="name(..)"/>
- <xsl:text> titleabbrev.</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
- </xsl:if>
- <xsl:apply-templates select="titleabbrev" mode="copy"/>
- </xsl:when>
- <xsl:when test="titleabbrev">
- <xsl:apply-templates select="titleabbrev" mode="copy"/>
- </xsl:when>
- <xsl:when test="following-sibling::titleabbrev">
- <xsl:apply-templates select="following-sibling::titleabbrev" mode="copy"/>
- </xsl:when>
- </xsl:choose>
-
- <xsl:choose>
- <xsl:when test="subtitle and following-sibling::subtitle">
- <xsl:if test="subtitle != following-sibling::subtitle">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Check </xsl:text>
- <xsl:value-of select="name(..)"/>
- <xsl:text> subtitle.</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
- </xsl:if>
- <xsl:apply-templates select="subtitle" mode="copy"/>
- </xsl:when>
- <xsl:when test="subtitle">
- <xsl:apply-templates select="subtitle" mode="copy"/>
- </xsl:when>
- <xsl:when test="following-sibling::subtitle">
- <xsl:apply-templates select="following-sibling::subtitle" mode="copy"/>
- </xsl:when>
- </xsl:choose>
-
- <xsl:apply-templates/>
- </info>
-</xsl:template>
-
-<xsl:template match="objectinfo|prefaceinfo|refsynopsisdivinfo
- |screeninfo|sidebarinfo"
- priority="200">
- <info>
- <xsl:call-template name="copy.attributes"/>
-
- <!-- titles can be inside or outside or both. fix that -->
- <xsl:choose>
- <xsl:when test="title and following-sibling::title">
- <xsl:if test="title != following-sibling::title">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Check </xsl:text>
- <xsl:value-of select="name(..)"/>
- <xsl:text> title.</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
- </xsl:if>
- <xsl:apply-templates select="title" mode="copy"/>
- </xsl:when>
- <xsl:when test="title">
- <xsl:apply-templates select="title" mode="copy"/>
- </xsl:when>
- <xsl:when test="following-sibling::title">
- <xsl:apply-templates select="following-sibling::title" mode="copy"/>
- </xsl:when>
- <xsl:otherwise>
- <!-- it's ok if there's no title on these -->
- </xsl:otherwise>
- </xsl:choose>
-
- <xsl:choose>
- <xsl:when test="titleabbrev and following-sibling::titleabbrev">
- <xsl:if test="titleabbrev != following-sibling::titleabbrev">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Check </xsl:text>
- <xsl:value-of select="name(..)"/>
- <xsl:text> titleabbrev.</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
- </xsl:if>
- <xsl:apply-templates select="titleabbrev" mode="copy"/>
- </xsl:when>
- <xsl:when test="titleabbrev">
- <xsl:apply-templates select="titleabbrev" mode="copy"/>
- </xsl:when>
- <xsl:when test="following-sibling::titleabbrev">
- <xsl:apply-templates select="following-sibling::titleabbrev" mode="copy"/>
- </xsl:when>
- </xsl:choose>
-
- <xsl:choose>
- <xsl:when test="subtitle and following-sibling::subtitle">
- <xsl:if test="subtitle != following-sibling::subtitle">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Check </xsl:text>
- <xsl:value-of select="name(..)"/>
- <xsl:text> subtitle.</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
- </xsl:if>
- <xsl:apply-templates select="subtitle" mode="copy"/>
- </xsl:when>
- <xsl:when test="subtitle">
- <xsl:apply-templates select="subtitle" mode="copy"/>
- </xsl:when>
- <xsl:when test="following-sibling::subtitle">
- <xsl:apply-templates select="following-sibling::subtitle" mode="copy"/>
- </xsl:when>
- </xsl:choose>
-
- <xsl:apply-templates/>
- </info>
-</xsl:template>
-
-<xsl:template match="refentryinfo"
- priority="200">
- <info>
- <xsl:call-template name="copy.attributes"/>
-
- <!-- titles can be inside or outside or both. fix that -->
- <xsl:if test="title">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Discarding title from refentryinfo!</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
- </xsl:if>
-
- <xsl:if test="titleabbrev">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Discarding titleabbrev from refentryinfo!</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
- </xsl:if>
-
- <xsl:if test="subtitle">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Discarding subtitle from refentryinfo!</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
- </xsl:if>
-
- <xsl:apply-templates/>
- </info>
-</xsl:template>
-
-<xsl:template match="refmiscinfo"
- priority="200">
- <refmiscinfo>
- <xsl:call-template name="copy.attributes">
- <xsl:with-param name="suppress" select="'class'"/>
- </xsl:call-template>
- <xsl:if test="@class">
- <xsl:choose>
- <xsl:when test="@class = 'source'
- or @class = 'version'
- or @class = 'manual'
- or @class = 'sectdesc'
- or @class = 'software'">
- <xsl:attribute name="class">
- <xsl:value-of select="@class"/>
- </xsl:attribute>
- </xsl:when>
- <xsl:otherwise>
- <xsl:attribute name="class">
- <xsl:value-of select="'other'"/>
- </xsl:attribute>
- <xsl:attribute name="otherclass">
- <xsl:value-of select="@class"/>
- </xsl:attribute>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:if>
- <xsl:apply-templates/>
- </refmiscinfo>
-</xsl:template>
-
-<xsl:template match="corpauthor" priority="200">
- <author>
- <xsl:call-template name="copy.attributes"/>
- <orgname>
- <xsl:apply-templates/>
- </orgname>
- </author>
-</xsl:template>
-
-<xsl:template match="corpname" priority="200">
- <orgname>
- <xsl:call-template name="copy.attributes"/>
- <xsl:apply-templates/>
- </orgname>
-</xsl:template>
-
-<xsl:template match="author[not(personname)]|editor[not(personname)]|othercredit[not(personname)]" priority="200">
- <xsl:copy>
- <xsl:call-template name="copy.attributes"/>
- <personname>
- <xsl:apply-templates select="honorific|firstname|surname|othername|lineage"/>
- </personname>
- <xsl:apply-templates select="*[not(self::honorific|self::firstname|self::surname
- |self::othername|self::lineage)]"/>
- </xsl:copy>
-</xsl:template>
-
-<xsl:template match="address|programlisting|screen|funcsynopsisinfo
- |classsynopsisinfo|literallayout" priority="200">
- <xsl:copy>
- <xsl:call-template name="copy.attributes">
- <xsl:with-param name="suppress" select="'format'"/>
- </xsl:call-template>
- <xsl:apply-templates/>
- </xsl:copy>
-</xsl:template>
-
-<xsl:template match="productname[@class]" priority="200">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Dropping class attribute from productname</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
- <xsl:copy>
- <xsl:call-template name="copy.attributes">
- <xsl:with-param name="suppress" select="'class'"/>
- </xsl:call-template>
- <xsl:apply-templates/>
- </xsl:copy>
-</xsl:template>
-
-<xsl:template match="dedication|preface|chapter|appendix|part|partintro
- |article|bibliography|glossary|glossdiv|index
- |reference[not(referenceinfo)]
- |book" priority="200">
- <xsl:choose>
- <xsl:when test="not(dedicationinfo|prefaceinfo|chapterinfo
- |appendixinfo|partinfo
- |articleinfo|artheader|bibliographyinfo
- |glossaryinfo|indexinfo
- |bookinfo)">
- <xsl:copy>
- <xsl:call-template name="copy.attributes"/>
- <xsl:if test="title|subtitle|titleabbrev">
- <info>
- <xsl:apply-templates select="title" mode="copy"/>
- <xsl:apply-templates select="titleabbrev" mode="copy"/>
- <xsl:apply-templates select="subtitle" mode="copy"/>
- <xsl:apply-templates select="abstract" mode="copy"/>
- </info>
- </xsl:if>
- <xsl:apply-templates/>
- </xsl:copy>
- </xsl:when>
- <xsl:otherwise>
- <xsl:copy>
- <xsl:call-template name="copy.attributes"/>
- <xsl:apply-templates/>
- </xsl:copy>
- </xsl:otherwise>
- </xsl:choose>
-</xsl:template>
-
-<xsl:template match="formalpara|figure|table[tgroup]|example|blockquote
- |caution|important|note|warning|tip
- |bibliodiv|glossarydiv|indexdiv
- |orderedlist|itemizedlist|variablelist|procedure
- |task|tasksummary|taskprerequisites|taskrelated
- |sidebar"
- priority="200">
- <xsl:choose>
- <xsl:when test="blockinfo">
- <xsl:copy>
- <xsl:call-template name="copy.attributes"/>
- <xsl:apply-templates/>
- </xsl:copy>
- </xsl:when>
- <xsl:otherwise>
- <xsl:copy>
- <xsl:call-template name="copy.attributes"/>
-
- <xsl:if test="title|titleabbrev|subtitle">
- <info>
- <xsl:apply-templates select="title" mode="copy"/>
- <xsl:apply-templates select="titleabbrev" mode="copy"/>
- <xsl:apply-templates select="subtitle" mode="copy"/>
- </info>
- </xsl:if>
-
- <xsl:apply-templates/>
- </xsl:copy>
- </xsl:otherwise>
- </xsl:choose>
-</xsl:template>
-
-<xsl:template match="equation" priority="200">
- <xsl:choose>
- <xsl:when test="not(title)">
- <xsl:call-template name="emit-message">
- <xsl:with-param
- name="message"
- >Convert equation without title to informal equation.</xsl:with-param>
- </xsl:call-template>
- <informalequation>
- <xsl:call-template name="copy.attributes"/>
- <xsl:apply-templates/>
- </informalequation>
- </xsl:when>
- <xsl:when test="blockinfo">
- <xsl:copy>
- <xsl:call-template name="copy.attributes"/>
- <xsl:apply-templates/>
- </xsl:copy>
- </xsl:when>
- <xsl:otherwise>
- <xsl:copy>
- <xsl:call-template name="copy.attributes"/>
- <info>
- <xsl:apply-templates select="title" mode="copy"/>
- <xsl:apply-templates select="titleabbrev" mode="copy"/>
- <xsl:apply-templates select="subtitle" mode="copy"/>
- </info>
- <xsl:apply-templates/>
- </xsl:copy>
- </xsl:otherwise>
- </xsl:choose>
-</xsl:template>
-
-<xsl:template match="sect1|sect2|sect3|sect4|sect5|section"
- priority="200">
- <section>
- <xsl:call-template name="copy.attributes"/>
-
- <xsl:if test="not(sect1info|sect2info|sect3info|sect4info|sect5info|sectioninfo)">
- <info>
- <xsl:apply-templates select="title" mode="copy"/>
- <xsl:apply-templates select="titleabbrev" mode="copy"/>
- <xsl:apply-templates select="subtitle" mode="copy"/>
- <xsl:apply-templates select="abstract" mode="copy"/>
- </info>
- </xsl:if>
- <xsl:apply-templates/>
- </section>
-</xsl:template>
-
-<xsl:template match="simplesect"
- priority="200">
- <simplesect>
- <xsl:call-template name="copy.attributes"/>
- <info>
- <xsl:apply-templates select="title" mode="copy"/>
- <xsl:apply-templates select="titleabbrev" mode="copy"/>
- <xsl:apply-templates select="subtitle" mode="copy"/>
- <xsl:apply-templates select="abstract" mode="copy"/>
- </info>
- <xsl:apply-templates/>
- </simplesect>
-</xsl:template>
-
-<xsl:template match="refsect1|refsect2|refsect3|refsection" priority="200">
- <refsection>
- <xsl:call-template name="copy.attributes"/>
-
- <xsl:if test="not(refsect1info|refsect2info|refsect3info|refsectioninfo)">
- <info>
- <xsl:apply-templates select="title" mode="copy"/>
- <xsl:apply-templates select="titleabbrev" mode="copy"/>
- <xsl:apply-templates select="subtitle" mode="copy"/>
- <xsl:apply-templates select="abstract" mode="copy"/>
- </info>
- </xsl:if>
- <xsl:apply-templates/>
- </refsection>
-</xsl:template>
-
-<xsl:template match="imagedata|videodata|audiodata|textdata" priority="200">
- <xsl:copy>
- <xsl:call-template name="copy.attributes">
- <xsl:with-param name="suppress" select="'srccredit'"/>
- </xsl:call-template>
- <xsl:if test="@srccredit">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Check conversion of srccredit </xsl:text>
- <xsl:text>(othercredit="srccredit").</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
- <info>
- <othercredit class="other" otherclass="srccredit">
- <orgname>???</orgname>
- <contrib>
- <xsl:value-of select="@srccredit"/>
- </contrib>
- </othercredit>
- </info>
- </xsl:if>
- </xsl:copy>
-</xsl:template>
-
-<xsl:template match="sgmltag" priority="200">
- <tag>
- <xsl:call-template name="copy.attributes"/>
- <xsl:if test="@class = 'sgmlcomment'">
- <xsl:attribute name="class">comment</xsl:attribute>
- </xsl:if>
- <xsl:apply-templates/>
- </tag>
-</xsl:template>
-
-<xsl:template match="inlinegraphic[@format='linespecific']" priority="210">
- <textobject>
- <textdata>
- <xsl:call-template name="copy.attributes"/>
- </textdata>
- </textobject>
-</xsl:template>
-
-<xsl:template match="inlinegraphic" priority="200">
- <inlinemediaobject>
- <imageobject>
- <imagedata>
- <xsl:call-template name="copy.attributes"/>
- </imagedata>
- </imageobject>
- </inlinemediaobject>
-</xsl:template>
-
-<xsl:template match="graphic[@format='linespecific']" priority="210">
- <mediaobject>
- <textobject>
- <textdata>
- <xsl:call-template name="copy.attributes"/>
- </textdata>
- </textobject>
- </mediaobject>
-</xsl:template>
-
-<xsl:template match="graphic" priority="200">
- <mediaobject>
- <imageobject>
- <imagedata>
- <xsl:call-template name="copy.attributes"/>
- </imagedata>
- </imageobject>
- </mediaobject>
-</xsl:template>
-
-<xsl:template match="pubsnumber" priority="200">
- <biblioid class="pubsnumber">
- <xsl:call-template name="copy.attributes"/>
- <xsl:apply-templates/>
- </biblioid>
-</xsl:template>
-
-<xsl:template match="invpartnumber" priority="200">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Converting invpartnumber to biblioid otherclass="invpartnumber".</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
- <biblioid class="other" otherclass="invpartnumber">
- <xsl:call-template name="copy.attributes"/>
- <xsl:apply-templates/>
- </biblioid>
-</xsl:template>
-
-<xsl:template match="contractsponsor" priority="200">
- <xsl:variable name="contractnum"
- select="preceding-sibling::contractnum|following-sibling::contractnum"/>
-
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Converting contractsponsor to othercredit="contractsponsor".</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
-
- <othercredit class="other" otherclass="contractsponsor">
- <orgname>
- <xsl:call-template name="copy.attributes"/>
- <xsl:apply-templates/>
- </orgname>
- <xsl:for-each select="$contractnum">
- <contrib role="contractnum">
- <xsl:apply-templates select="node()"/>
- </contrib>
- </xsl:for-each>
- </othercredit>
-</xsl:template>
-
-<xsl:template match="contractnum" priority="200">
- <xsl:if test="not(preceding-sibling::contractsponsor
- |following-sibling::contractsponsor)
- and not(preceding-sibling::contractnum)">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Converting contractnum to othercredit="contractnum".</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
-
- <othercredit class="other" otherclass="contractnum">
- <orgname>???</orgname>
- <xsl:for-each select="self::contractnum
- |preceding-sibling::contractnum
- |following-sibling::contractnum">
- <contrib>
- <xsl:apply-templates select="node()"/>
- </contrib>
- </xsl:for-each>
- </othercredit>
- </xsl:if>
-</xsl:template>
-
-<xsl:template match="isbn|issn" priority="200">
- <biblioid class="{local-name(.)}">
- <xsl:call-template name="copy.attributes"/>
- <xsl:apply-templates/>
- </biblioid>
-</xsl:template>
-
-<xsl:template match="biblioid[count(*) = 1
- and ulink
- and normalize-space(text()) = '']" priority="200">
- <biblioid xlink:href="{ulink/@url}">
- <xsl:call-template name="copy.attributes"/>
- <xsl:apply-templates select="ulink/node()"/>
- </biblioid>
-</xsl:template>
-
-<xsl:template match="authorblurb" priority="200">
- <personblurb>
- <xsl:call-template name="copy.attributes"/>
- <xsl:apply-templates/>
- </personblurb>
-</xsl:template>
-
-<xsl:template match="collabname" priority="200">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Check conversion of collabname </xsl:text>
- <xsl:text>(orgname role="collabname").</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
- <orgname role="collabname">
- <xsl:call-template name="copy.attributes"/>
- <xsl:apply-templates/>
- </orgname>
-</xsl:template>
-
-<xsl:template match="modespec" priority="200">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Discarding modespec (</xsl:text>
- <xsl:value-of select="."/>
- <xsl:text>).</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
-</xsl:template>
-
-<xsl:template match="mediaobjectco" priority="200">
- <mediaobject>
- <xsl:copy-of select="@*"/>
- <xsl:apply-templates/>
- </mediaobject>
-</xsl:template>
-
-<xsl:template match="remark" priority="200">
- <!-- get rid of any embedded markup -->
- <remark>
- <xsl:copy-of select="@*"/>
- <xsl:value-of select="."/>
- </remark>
-</xsl:template>
-
-<xsl:template match="biblioentry/title
- |bibliomset/title
- |biblioset/title
- |bibliomixed/title" priority="400">
- <citetitle>
- <xsl:copy-of select="@*"/>
- <xsl:apply-templates/>
- </citetitle>
-</xsl:template>
-
-<xsl:template match="biblioentry/titleabbrev|biblioentry/subtitle
- |bibliomset/titleabbrev|bibliomset/subtitle
- |biblioset/titleabbrev|biblioset/subtitle
- |bibliomixed/titleabbrev|bibliomixed/subtitle"
- priority="400">
- <xsl:copy>
- <xsl:copy-of select="@*"/>
- <xsl:apply-templates/>
- </xsl:copy>
-</xsl:template>
-
-<xsl:template match="biblioentry/contrib
- |bibliomset/contrib
- |bibliomixed/contrib" priority="200">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Check conversion of contrib </xsl:text>
- <xsl:text>(othercontrib="contrib").</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
- <othercredit class="other" otherclass="contrib">
- <orgname>???</orgname>
- <contrib>
- <xsl:call-template name="copy.attributes"/>
- <xsl:apply-templates/>
- </contrib>
- </othercredit>
-</xsl:template>
-
-<xsl:template match="link" priority="200">
- <xsl:copy>
- <xsl:call-template name="copy.attributes"/>
- <xsl:apply-templates/>
- </xsl:copy>
-</xsl:template>
-
-<xsl:template match="ulink" priority="200">
- <xsl:choose>
- <xsl:when test="node()">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Converting ulink to link.</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
-
- <link xlink:href="{@url}">
- <xsl:call-template name="copy.attributes">
- <xsl:with-param name="suppress" select="'url'"/>
- </xsl:call-template>
- <xsl:apply-templates/>
- </link>
- </xsl:when>
- <xsl:otherwise>
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Converting ulink to uri.</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
-
- <uri xlink:href="{@url}">
- <xsl:call-template name="copy.attributes">
- <xsl:with-param name="suppress" select="'url'"/>
- </xsl:call-template>
- <xsl:value-of select="@url"/>
- </uri>
- </xsl:otherwise>
- </xsl:choose>
-</xsl:template>
-
-<xsl:template match="olink" priority="200">
- <xsl:if test="@linkmode">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Discarding linkmode on olink.</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
- </xsl:if>
-
- <xsl:choose>
- <xsl:when test="@targetdocent">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Converting olink targetdocent to targetdoc.</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
-
- <olink targetdoc="{unparsed-entity-uri(@targetdocent)}">
- <xsl:for-each select="@*">
- <xsl:if test="name(.) != 'targetdocent'
- and name(.) != 'linkmode'">
- <xsl:copy/>
- </xsl:if>
- </xsl:for-each>
- <xsl:apply-templates/>
- </olink>
- </xsl:when>
- <xsl:otherwise>
- <olink>
- <xsl:for-each select="@*">
- <xsl:if test="name(.) != 'linkmode'">
- <xsl:copy/>
- </xsl:if>
- </xsl:for-each>
- <xsl:apply-templates/>
- </olink>
- </xsl:otherwise>
- </xsl:choose>
-</xsl:template>
-
-<xsl:template match="biblioentry/firstname
- |biblioentry/surname
- |biblioentry/othername
- |biblioentry/lineage
- |biblioentry/honorific
- |bibliomset/firstname
- |bibliomset/surname
- |bibliomset/othername
- |bibliomset/lineage
- |bibliomset/honorific" priority="200">
- <xsl:choose>
- <xsl:when test="preceding-sibling::firstname
- |preceding-sibling::surname
- |preceding-sibling::othername
- |preceding-sibling::lineage
- |preceding-sibling::honorific">
- <!-- nop -->
- </xsl:when>
- <xsl:otherwise>
- <personname>
- <xsl:apply-templates select="../firstname
- |../surname
- |../othername
- |../lineage
- |../honorific" mode="copy"/>
- </personname>
- </xsl:otherwise>
- </xsl:choose>
-</xsl:template>
-
-<xsl:template match="areaset" priority="200">
- <xsl:copy>
- <xsl:call-template name="copy.attributes">
- <xsl:with-param name="suppress" select="'coords'"/>
- </xsl:call-template>
- <xsl:apply-templates/>
- </xsl:copy>
-</xsl:template>
-
-<xsl:template match="date|pubdate" priority="200">
- <xsl:variable name="rp1" select="substring-before(normalize-space(.), ' ')"/>
- <xsl:variable name="rp2"
- select="substring-before(substring-after(normalize-space(.), ' '),
- ' ')"/>
- <xsl:variable name="rp3"
- select="substring-after(substring-after(normalize-space(.), ' '), ' ')"/>
-
- <xsl:variable name="p1">
- <xsl:choose>
- <xsl:when test="contains($rp1, ',')">
- <xsl:value-of select="substring-before($rp1, ',')"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="$rp1"/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
-
- <xsl:variable name="p2">
- <xsl:choose>
- <xsl:when test="contains($rp2, ',')">
- <xsl:value-of select="substring-before($rp2, ',')"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="$rp2"/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
-
- <xsl:variable name="p3">
- <xsl:choose>
- <xsl:when test="contains($rp3, ',')">
- <xsl:value-of select="substring-before($rp3, ',')"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="$rp3"/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
-
- <xsl:variable name="date">
- <xsl:choose>
- <xsl:when test="string($p1+1) != 'NaN' and string($p3+1) != 'NaN'">
- <xsl:choose>
- <xsl:when test="$p2 = 'Jan' or $p2 = 'January'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-01-</xsl:text>
- <xsl:number value="$p1" format="01"/>
- </xsl:when>
- <xsl:when test="$p2 = 'Feb' or $p2 = 'February'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-02-</xsl:text>
- <xsl:number value="$p1" format="01"/>
- </xsl:when>
- <xsl:when test="$p2 = 'Mar' or $p2 = 'March'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-03-</xsl:text>
- <xsl:number value="$p1" format="01"/>
- </xsl:when>
- <xsl:when test="$p2 = 'Apr' or $p2 = 'April'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-04-</xsl:text>
- <xsl:number value="$p1" format="01"/>
- </xsl:when>
- <xsl:when test="$p2 = 'May'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-05-</xsl:text>
- <xsl:number value="$p1" format="01"/>
- </xsl:when>
- <xsl:when test="$p2 = 'Jun' or $p2 = 'June'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-06-</xsl:text>
- <xsl:number value="$p1" format="01"/>
- </xsl:when>
- <xsl:when test="$p2 = 'Jul' or $p2 = 'July'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-07-</xsl:text>
- <xsl:number value="$p1" format="01"/>
- </xsl:when>
- <xsl:when test="$p2 = 'Aug' or $p2 = 'August'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-08-</xsl:text>
- <xsl:number value="$p1" format="01"/>
- </xsl:when>
- <xsl:when test="$p2 = 'Sep' or $p2 = 'September'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-09-</xsl:text>
- <xsl:number value="$p1" format="01"/>
- </xsl:when>
- <xsl:when test="$p2 = 'Oct' or $p2 = 'October'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-10-</xsl:text>
- <xsl:number value="$p1" format="01"/>
- </xsl:when>
- <xsl:when test="$p2 = 'Nov' or $p2 = 'November'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-11-</xsl:text>
- <xsl:number value="$p1" format="01"/>
- </xsl:when>
- <xsl:when test="$p2 = 'Dec' or $p2 = 'December'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-12-</xsl:text>
- <xsl:number value="$p1" format="01"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:apply-templates/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:when>
- <xsl:when test="string($p2+1) != 'NaN' and string($p3+1) != 'NaN'">
- <xsl:choose>
- <xsl:when test="$p1 = 'Jan' or $p1 = 'January'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-01-</xsl:text>
- <xsl:number value="$p2" format="01"/>
- </xsl:when>
- <xsl:when test="$p1 = 'Feb' or $p1 = 'February'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-02-</xsl:text>
- <xsl:number value="$p2" format="01"/>
- </xsl:when>
- <xsl:when test="$p1 = 'Mar' or $p1 = 'March'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-03-</xsl:text>
- <xsl:number value="$p2" format="01"/>
- </xsl:when>
- <xsl:when test="$p1 = 'Apr' or $p1 = 'April'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-04-</xsl:text>
- <xsl:number value="$p2" format="01"/>
- </xsl:when>
- <xsl:when test="$p1 = 'May'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-05-</xsl:text>
- <xsl:number value="$p2" format="01"/>
- </xsl:when>
- <xsl:when test="$p1 = 'Jun' or $p1 = 'June'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-06-</xsl:text>
- <xsl:number value="$p2" format="01"/>
- </xsl:when>
- <xsl:when test="$p1 = 'Jul' or $p1 = 'July'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-07-</xsl:text>
- <xsl:number value="$p2" format="01"/>
- </xsl:when>
- <xsl:when test="$p1 = 'Aug' or $p1 = 'August'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-08-</xsl:text>
- <xsl:number value="$p2" format="01"/>
- </xsl:when>
- <xsl:when test="$p1 = 'Sep' or $p1 = 'September'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-09-</xsl:text>
- <xsl:number value="$p2" format="01"/>
- </xsl:when>
- <xsl:when test="$p1 = 'Oct' or $p1 = 'October'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-10-</xsl:text>
- <xsl:number value="$p2" format="01"/>
- </xsl:when>
- <xsl:when test="$p1 = 'Nov' or $p1 = 'November'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-11-</xsl:text>
- <xsl:number value="$p2" format="01"/>
- </xsl:when>
- <xsl:when test="$p1 = 'Dec' or $p1 = 'December'">
- <xsl:number value="$p3" format="0001"/>
- <xsl:text>-12-</xsl:text>
- <xsl:number value="$p2" format="01"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:apply-templates/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:when>
- <xsl:otherwise>
- <xsl:apply-templates/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
-
- <xsl:choose>
- <xsl:when test="normalize-space($date) != normalize-space(.)">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Converted </xsl:text>
- <xsl:value-of select="normalize-space(.)"/>
- <xsl:text> into </xsl:text>
- <xsl:value-of select="$date"/>
- <xsl:text> for </xsl:text>
- <xsl:value-of select="name(.)"/>
- </xsl:with-param>
- </xsl:call-template>
-
- <xsl:copy>
- <xsl:copy-of select="@*"/>
- <xsl:value-of select="$date"/>
- </xsl:copy>
- </xsl:when>
-
- <xsl:when test="$defaultDate != ''">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Unparseable date: </xsl:text>
- <xsl:value-of select="normalize-space(.)"/>
- <xsl:text> in </xsl:text>
- <xsl:value-of select="name(.)"/>
- <xsl:text> (Using default: </xsl:text>
- <xsl:value-of select="$defaultDate"/>
- <xsl:text>)</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
-
- <xsl:copy>
- <xsl:copy-of select="@*"/>
- <xsl:copy-of select="$defaultDate"/>
- <xsl:comment>
- <xsl:value-of select="."/>
- </xsl:comment>
- </xsl:copy>
- </xsl:when>
-
- <xsl:otherwise>
- <!-- these don't really matter anymore
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Unparseable date: </xsl:text>
- <xsl:value-of select="normalize-space(.)"/>
- <xsl:text> in </xsl:text>
- <xsl:value-of select="name(.)"/>
- </xsl:with-param>
- </xsl:call-template>
- -->
- <xsl:copy>
- <xsl:copy-of select="@*"/>
- <xsl:apply-templates/>
- </xsl:copy>
- </xsl:otherwise>
- </xsl:choose>
-</xsl:template>
-
-<xsl:template match="title|subtitle|titleabbrev" priority="300">
- <!-- nop -->
-</xsl:template>
-
-<xsl:template match="abstract" priority="300">
- <xsl:if test="not(contains(name(parent::*),'info'))">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Check abstract; moved into info correctly?</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
- </xsl:if>
-</xsl:template>
-
-<xsl:template match="indexterm">
- <!-- don't copy the defaulted significance='normal' attribute -->
- <indexterm>
- <xsl:call-template name="copy.attributes">
- <xsl:with-param name="suppress">
- <xsl:if test="@significance = 'normal'">significance</xsl:if>
- </xsl:with-param>
- </xsl:call-template>
- <xsl:apply-templates/>
- </indexterm>
-</xsl:template>
-
-<xsl:template match="ackno" priority="200">
- <acknowledgements>
- <xsl:copy-of select="@*"/>
- <para>
- <xsl:apply-templates/>
- </para>
- </acknowledgements>
-</xsl:template>
-
-<xsl:template match="lot|lotentry|tocback|tocchap|tocfront|toclevel1|
- toclevel2|toclevel3|toclevel4|toclevel5|tocpart" priority="200">
- <tocdiv>
- <xsl:copy-of select="@*"/>
- <xsl:apply-templates/>
- </tocdiv>
-</xsl:template>
-
-<xsl:template match="action" priority="200">
- <phrase remap="action">
- <xsl:call-template name="copy.attributes"/>
- <xsl:apply-templates/>
- </phrase>
-</xsl:template>
-
-<xsl:template match="beginpage" priority="200">
- <xsl:comment> beginpage pagenum=<xsl:value-of select="@pagenum"/> </xsl:comment>
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Replacing beginpage with comment</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
-</xsl:template>
-
-<xsl:template match="structname|structfield" priority="200">
- <varname remap="{local-name(.)}">
- <xsl:call-template name="copy.attributes"/>
- <xsl:apply-templates/>
- </varname>
-</xsl:template>
-
-<!-- ====================================================================== -->
-
-<!-- 6 Feb 2008, ndw changed mode=copy so that it only copies the first level,
- then it switches back to "normal" mode so that other rewriting templates
- catch embedded fixes -->
-
-<!--
-<xsl:template match="ulink" priority="200" mode="copy">
- <xsl:choose>
- <xsl:when test="node()">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Converting ulink to phrase.</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
-
- <phrase xlink:href="{@url}">
- <xsl:call-template name="copy.attributes">
- <xsl:with-param name="suppress" select="'url'"/>
- </xsl:call-template>
- <xsl:apply-templates/>
- </phrase>
- </xsl:when>
- <xsl:otherwise>
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Converting ulink to uri.</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
-
- <uri xlink:href="{@url}">
- <xsl:call-template name="copy.attributes">
- <xsl:with-param name="suppress" select="'url'"/>
- </xsl:call-template>
- <xsl:value-of select="@url"/>
- </uri>
- </xsl:otherwise>
- </xsl:choose>
-</xsl:template>
-
-<xsl:template match="sgmltag" priority="200" mode="copy">
- <tag>
- <xsl:call-template name="copy.attributes"/>
- <xsl:apply-templates/>
- </tag>
-</xsl:template>
--->
-
-<xsl:template match="*" mode="copy">
- <xsl:copy>
- <xsl:call-template name="copy.attributes"/>
- <xsl:apply-templates/>
- </xsl:copy>
-</xsl:template>
-
-<!--
-<xsl:template match="comment()|processing-instruction()|text()" mode="copy">
- <xsl:copy/>
-</xsl:template>
--->
-
-<!-- ====================================================================== -->
-
-<xsl:template match="*">
- <xsl:copy>
- <xsl:call-template name="copy.attributes"/>
- <xsl:apply-templates/>
- </xsl:copy>
-</xsl:template>
-
-<xsl:template match="comment()|processing-instruction()|text()">
- <xsl:copy/>
-</xsl:template>
-
-<!-- ====================================================================== -->
-
-<xsl:template name="copy.attributes">
- <xsl:param name="src" select="."/>
- <xsl:param name="suppress" select="''"/>
-
- <xsl:for-each select="$src/@*">
- <xsl:choose>
- <xsl:when test="local-name(.) = 'moreinfo'">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Discarding moreinfo on </xsl:text>
- <xsl:value-of select="local-name($src)"/>
- </xsl:with-param>
- </xsl:call-template>
- </xsl:when>
- <xsl:when test="local-name(.) = 'lang'">
- <xsl:attribute name="xml:lang">
- <xsl:value-of select="."/>
- </xsl:attribute>
- </xsl:when>
- <xsl:when test="local-name(.) = 'id'">
- <xsl:attribute name="xml:id">
- <xsl:value-of select="."/>
- </xsl:attribute>
- </xsl:when>
- <xsl:when test="$suppress = local-name(.)"/>
- <xsl:when test="local-name(.) = 'float'">
- <xsl:choose>
- <xsl:when test=". = '1'">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Discarding float on </xsl:text>
- <xsl:value-of select="local-name($src)"/>
- </xsl:with-param>
- </xsl:call-template>
- <xsl:if test="not($src/@floatstyle)">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Adding floatstyle='normal' on </xsl:text>
- <xsl:value-of select="local-name($src)"/>
- </xsl:with-param>
- </xsl:call-template>
- <xsl:attribute name="floatstyle">
- <xsl:text>normal</xsl:text>
- </xsl:attribute>
- </xsl:if>
- </xsl:when>
- <xsl:when test=". = '0'">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Discarding float on </xsl:text>
- <xsl:value-of select="local-name($src)"/>
- </xsl:with-param>
- </xsl:call-template>
- </xsl:when>
- <xsl:otherwise>
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Discarding float on </xsl:text>
- <xsl:value-of select="local-name($src)"/>
- </xsl:with-param>
- </xsl:call-template>
- <xsl:if test="not($src/@floatstyle)">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Adding floatstyle='</xsl:text>
- <xsl:value-of select="."/>
- <xsl:text>' on </xsl:text>
- <xsl:value-of select="local-name($src)"/>
- </xsl:with-param>
- </xsl:call-template>
- <xsl:attribute name="floatstyle">
- <xsl:value-of select="."/>
- </xsl:attribute>
- </xsl:if>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:when>
- <xsl:when test="local-name(.) = 'entityref'">
- <xsl:attribute name="fileref">
- <xsl:value-of select="unparsed-entity-uri(@entityref)"/>
- </xsl:attribute>
- </xsl:when>
-
- <xsl:when test="local-name($src) = 'simplemsgentry'
- and local-name(.) = 'audience'">
- <xsl:attribute name="msgaud">
- <xsl:value-of select="."/>
- </xsl:attribute>
- </xsl:when>
- <xsl:when test="local-name($src) = 'simplemsgentry'
- and local-name(.) = 'origin'">
- <xsl:attribute name="msgorig">
- <xsl:value-of select="."/>
- </xsl:attribute>
- </xsl:when>
- <xsl:when test="local-name($src) = 'simplemsgentry'
- and local-name(.) = 'level'">
- <xsl:attribute name="msglevel">
- <xsl:value-of select="."/>
- </xsl:attribute>
- </xsl:when>
-
- <!-- * for upgrading XSL litprog params documentation -->
- <xsl:when test="local-name($src) = 'refmiscinfo'
- and local-name(.) = 'role'
- and . = 'type'
- ">
- <xsl:call-template name="emit-message">
- <xsl:with-param name="message">
- <xsl:text>Converting refmiscinfo@role=type to </xsl:text>
- <xsl:text>@class=other,otherclass=type</xsl:text>
- </xsl:with-param>
- </xsl:call-template>
- <xsl:attribute name="class">other</xsl:attribute>
- <xsl:attribute name="otherclass">type</xsl:attribute>
- </xsl:when>
-
- <xsl:otherwise>
- <xsl:copy/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:for-each>
-</xsl:template>
-
-<!-- ====================================================================== -->
-
-<xsl:template match="*" mode="addNS">
- <xsl:choose>
- <xsl:when test="namespace-uri(.) = ''">
- <xsl:element name="{local-name(.)}"
- namespace="http://docbook.org/ns/docbook">
- <xsl:if test="not(parent::*)">
- <xsl:attribute name="version">5.0</xsl:attribute>
- </xsl:if>
- <xsl:copy-of select="@*"/>
- <xsl:apply-templates mode="addNS"/>
- </xsl:element>
- </xsl:when>
- <xsl:otherwise>
- <xsl:copy>
- <xsl:if test="not(parent::*)">
- <xsl:attribute name="version">5.0</xsl:attribute>
- </xsl:if>
- <xsl:copy-of select="@*"/>
- <xsl:apply-templates mode="addNS"/>
- </xsl:copy>
- </xsl:otherwise>
- </xsl:choose>
-</xsl:template>
-
-<xsl:template match="comment()|processing-instruction()|text()" mode="addNS">
- <xsl:copy/>
-</xsl:template>
-
-<!-- ====================================================================== -->
-
-<xsl:template name="emit-message">
- <xsl:param name="message"/>
- <xsl:message>
- <xsl:value-of select="$message"/>
- <xsl:text> (</xsl:text>
- <xsl:value-of select="$rootid"/>
- <xsl:text>)</xsl:text>
- </xsl:message>
-</xsl:template>
-
-</xsl:stylesheet>
+++ /dev/null
-package org.argeo.app.odk;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.nio.charset.StandardCharsets;
-
-import javax.jcr.ImportUUIDBehavior;
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.Property;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.app.api.EntityMimeType;
-import org.argeo.app.api.EntityType;
-import org.argeo.cms.util.DigestUtils;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.jcr.JcrxApi;
-
-/** Utilities around ODK. */
-public class OdkUtils {
- private final static CmsLog log = CmsLog.getLog(OdkUtils.class);
-
- public static Node loadOdkForm(Node formBase, String name, InputStream in, InputStream... additionalNodes)
- throws RepositoryException, IOException {
- if (!formBase.isNodeType(EntityType.formSet.get()))
- throw new IllegalArgumentException(
- "Parent path " + formBase + " must be of type " + EntityType.formSet.get());
- Node form = JcrUtils.getOrAdd(formBase, name, OrxListName.xform.get(), NodeType.MIX_VERSIONABLE);
-
- String previousCsum = JcrxApi.getChecksum(form, JcrxApi.MD5);
- String previousFormId = Jcr.get(form, OrxListName.formID.get());
- String previousFormVersion = Jcr.get(form, OrxListName.version.get());
-
- Session s = formBase.getSession();
- s.importXML(form.getPath(), in, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
-
- for (InputStream additionalIn : additionalNodes) {
- s.importXML(form.getPath(), additionalIn, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
- }
- s.save();
-
- // manage instances
- // NodeIterator instances =
- // form.getNodes("h:html/h:head/xforms:model/xforms:instance");
- NodeIterator instances = form.getNode("h:html/h:head/xforms:model").getNodes("xforms:instance");
- Node primaryInstance = null;
- while (instances.hasNext()) {
- Node instance = instances.nextNode();
- if (primaryInstance == null) {
- primaryInstance = instance;
- } else {// secondary instances
- String instanceId = instance.getProperty("id").getString();
- URI instanceUri = null;
- if (instance.hasProperty("src"))
- try {
- instanceUri = new URI(instance.getProperty("src").getString());
- } catch (URISyntaxException e) {
- throw new IllegalArgumentException("Instance " + instanceId + " has a badly formatted URI", e);
- }
- if (instanceUri != null) {
- if ("jr".equals(instanceUri.getScheme())) {
- String uuid;
- String mimeType;
- String encoding = StandardCharsets.UTF_8.name();
- String type = instanceUri.getHost();
- String path = instanceUri.getPath();
- if ("file".equals(type)) {
- if (!path.endsWith(".xml"))
- throw new IllegalArgumentException("File uri " + instanceUri + " must end with .xml");
- // Work around bug in ODK Collect not supporting paths
- // path = path.substring(0, path.length() - ".xml".length());
- // Node target = file.getSession().getNode(path);
- uuid = path.substring(1, path.length() - ".xml".length());
- mimeType = EntityMimeType.XML.getMimeType();
- } else if ("file-csv".equals(type)) {
- if (!path.endsWith(".csv"))
- throw new IllegalArgumentException("File uri " + instanceUri + " must end with .csv");
- // Work around bug in ODK Collect not supporting paths
- // path = path.substring(0, path.length() - ".csv".length());
- // Node target = file.getSession().getNode(path);
- uuid = path.substring(1, path.length() - ".csv".length());
- mimeType = EntityMimeType.CSV.getMimeType();
- } else {
- throw new IllegalArgumentException("Unsupported instance type " + type);
- }
- Node manifest = JcrUtils.getOrAdd(form, OrxManifestName.manifest.name(),
- OrxManifestName.manifest.get());
- Node file = JcrUtils.getOrAdd(manifest, instanceId);
- file.addMixin(NodeType.MIX_MIMETYPE);
- file.setProperty(Property.JCR_MIMETYPE, mimeType);
- file.setProperty(Property.JCR_ENCODING, encoding);
- Node target = file.getSession().getNodeByIdentifier(uuid);
-
-// if (target.isNodeType(NodeType.NT_QUERY)) {
-// Query query = target.getSession().getWorkspace().getQueryManager().getQuery(target);
-// query.setLimit(10);
-// QueryResult queryResult = query.execute();
-// RowIterator rit = queryResult.getRows();
-// while (rit.hasNext()) {
-// Row row = rit.nextRow();
-// for (Value value : row.getValues()) {
-// System.out.print(value.getString());
-// System.out.print(',');
-// }
-// System.out.print('\n');
-// }
-//
-// }
-
- if (target.isNodeType(NodeType.MIX_REFERENCEABLE)) {
- file.setProperty(Property.JCR_ID, target);
- if (file.hasProperty(Property.JCR_PATH))
- file.getProperty(Property.JCR_PATH).remove();
- } else {
- file.setProperty(Property.JCR_PATH, target.getPath());
- if (file.hasProperty(Property.JCR_ID))
- file.getProperty(Property.JCR_ID).remove();
- }
- }
- }
- }
- }
-
- if (primaryInstance == null)
- throw new IllegalArgumentException("No primary instance found in " + form);
- if (!primaryInstance.hasNodes())
- throw new IllegalArgumentException("No data found in primary instance of " + form);
- NodeIterator primaryInstanceChildren = primaryInstance.getNodes();
- Node data = primaryInstanceChildren.nextNode();
- if (primaryInstanceChildren.hasNext())
- throw new IllegalArgumentException("More than one data found in primary instance of " + form);
- String formId = data.getProperty("id").getString();
- if (previousFormId != null && !formId.equals(previousFormId))
- log.warn("Form id of " + form + " changed from " + previousFormId + " to " + formId);
- form.setProperty(OrxListName.formID.get(), formId);
- String formVersion = data.getProperty("version").getString();
-
- if (previousCsum == null)// save before checksuming
- s.save();
- String newCsum;
- try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
- s.exportDocumentView(form.getPath() + "/" + OdkNames.H_HTML, out, true, false);
- newCsum = DigestUtils.digest(DigestUtils.MD5, out.toByteArray());
- }
- if (previousCsum == null) {
- JcrxApi.addChecksum(form, newCsum);
- JcrUtils.updateLastModified(form);
- form.setProperty(OrxListName.version.get(), formVersion);
- s.save();
- s.getWorkspace().getVersionManager().checkpoint(form.getPath());
- if (log.isDebugEnabled())
- log.debug("New form " + form);
- } else {
- if (newCsum.equals(previousCsum)) {
- // discard
- s.refresh(false);
- if (log.isDebugEnabled())
- log.debug("Unmodified form " + form);
- return form;
- } else {
- if (formVersion.equals(previousFormVersion)) {
- s.refresh(false);
- throw new IllegalArgumentException("Form " + form + " has been changed but version " + formVersion
- + " has not been changed, discarding changes...");
- }
- form.setProperty(OrxListName.version.get(), formVersion);
- JcrxApi.addChecksum(form, newCsum);
- JcrUtils.updateLastModified(form);
- s.save();
- s.getWorkspace().getVersionManager().checkpoint(form.getPath());
- if (log.isDebugEnabled()) {
- log.debug("Updated form " + form);
- log.debug("Previous csum " + previousCsum);
- log.debug("New csum " + newCsum);
- }
- }
- }
- return form;
- }
-
- /** Singleton. */
- private OdkUtils() {
-
- }
-
-}
package org.argeo.app.xforms;
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
+import org.argeo.api.acr.Content;
/** Called when a user has received a new form submission. */
public interface FormSubmissionListener {
* Called after a form submission has been stored in the user area. The
* submission will be deleted if any exception is thrown.
*/
- void formSubmissionReceived(Node node) throws RepositoryException;
+ void formSubmissionReceived(Content content);
}
+++ /dev/null
-package org.argeo.internal.app.core;
-
-import javax.jcr.Node;
-
-import org.argeo.api.acr.Content;
-import org.argeo.api.acr.ContentSession;
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.api.cms.CmsSession;
-import org.argeo.app.api.AppUserState;
-import org.argeo.app.core.SuiteUtils;
-import org.argeo.cms.acr.ContentUtils;
-import org.argeo.cms.jcr.acr.JcrContentProvider;
-import org.argeo.jcr.Jcr;
-
-public class AppUserStateImpl implements AppUserState {
- private JcrContentProvider jcrContentProvider;
-
- @Override
- public Content getOrCreateSessionDir(ContentSession contentSession, CmsSession session) {
- Node userDirNode = jcrContentProvider.doInAdminSession((adminSession) -> {
- Node node = SuiteUtils.getOrCreateCmsSessionNode(adminSession, session);
- return node;
- });
- Content userDir = contentSession
- .get(ContentUtils.SLASH + CmsConstants.SYS_WORKSPACE + Jcr.getPath(userDirNode));
- return userDir;
- }
-
- public void setJcrContentProvider(JcrContentProvider jcrContentProvider) {
- this.jcrContentProvider = jcrContentProvider;
- }
-
-}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.app.jcr</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.argeo.internal.app.jcr.appUserState">
+ <implementation class="org.argeo.internal.app.jcr.AppUserStateImpl"/>
+ <service>
+ <provide interface="org.argeo.app.api.AppUserState"/>
+ </service>
+ <reference bind="setJcrContentProvider" cardinality="1..1" interface="org.argeo.cms.jcr.acr.JcrContentProvider" name="JcrContentProvider" policy="static"/>
+</scr:component>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" immediate="true" name="Suite Maintenance Service">
+ <implementation class="org.argeo.internal.app.jcr.SuiteMaintenanceService"/>
+ <reference bind="setRepository" cardinality="1..1" interface="javax.jcr.Repository" name="Repository" policy="static" target="(cn=ego)"/>
+ <reference bind="setUserTransaction" cardinality="1..1" interface="org.argeo.api.cms.transaction.WorkTransaction" name="WorkTransaction" policy="static"/>
+ <reference bind="setUserAdmin" cardinality="1..1" interface="org.osgi.service.useradmin.UserAdmin" name="UserAdmin" policy="static"/>
+ <reference bind="setContentRepository" cardinality="1..1" interface="org.argeo.api.acr.spi.ProvidedRepository" name="ContentRepository" policy="static"/>
+</scr:component>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" immediate="true" name="Suite Terms Manager">
+ <implementation class="org.argeo.app.jcr.terms.SuiteTermsManager"/>
+ <reference bind="setRepository" cardinality="1..1" interface="javax.jcr.Repository" name="Repository" policy="static" target="(cn=ego)"/>
+ <service>
+ <provide interface="org.argeo.app.api.TermsManager"/>
+ </service>
+</scr:component>
--- /dev/null
+Service-Component:\
+OSGI-INF/termsManager.xml,\
+OSGI-INF/maintenanceService.xml,\
+OSGI-INF/appUserState.xml,\
+
+Import-Package:\
+javax.jcr.nodetype,\
+javax.jcr.security,\
+org.apache.jackrabbit.*;version="[1,4)",\
+org.argeo.cms.acr,\
+*
\ No newline at end of file
--- /dev/null
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
--- /dev/null
+package org.argeo.app.jcr;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.ImportUUIDBehavior;
+import javax.jcr.ItemExistsException;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.app.api.EntityType;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.maintenance.AbstractMaintenanceService;
+
+/** Base for custom initialisations. */
+public abstract class CustomMaintenanceService extends AbstractMaintenanceService {
+ private final static CmsLog log = CmsLog.getLog(AbstractMaintenanceService.class);
+
+ protected List<String> getTypologies() {
+ return new ArrayList<>();
+ }
+
+ protected String getTypologiesLoadBase() {
+ return "";
+ }
+
+ protected void loadTypologies(Node customBaseNode) throws RepositoryException, IOException {
+ List<String> typologies = getTypologies();
+ if (!typologies.isEmpty()) {
+ Node termsBase = JcrUtils.getOrAdd(customBaseNode, EntityType.terms.name(), EntityType.typologies.get());
+ for (String terms : typologies) {
+ loadTerms(termsBase, terms);
+ }
+ // TODO do not save here, so that upper layers can decide when to save
+ termsBase.getSession().save();
+ }
+ }
+
+ protected void loadTerms(Node termsBase, String name) throws IOException, RepositoryException {
+ try {
+// if (termsBase.hasNode(name))
+// return;
+ String typologiesLoadBase = getTypologiesLoadBase();
+ if (typologiesLoadBase.contains("/") && !typologiesLoadBase.endsWith("/"))
+ typologiesLoadBase = typologiesLoadBase + "/";
+ String termsLoadPath = typologiesLoadBase + name + ".xml";
+ URL termsUrl = getClass().getResource(termsLoadPath);
+ if (termsUrl == null)
+ throw new IllegalArgumentException("Terms '" + name + "' not found.");
+ try (InputStream in = termsUrl.openStream()) {
+ termsBase.getSession().importXML(termsBase.getPath(), in,
+ ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
+ } catch (ItemExistsException e) {
+ log.warn("Terms " + name + " exists with another UUID, removing it...");
+ termsBase.getNode(name).remove();
+ try (InputStream in = termsUrl.openStream()) {
+ termsBase.getSession().importXML(termsBase.getPath(), in,
+ ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
+ }
+ }
+ if (log.isDebugEnabled())
+ log.debug("Terms '" + name + "' loaded.");
+ // TODO do not save here, so that upper layers can decide when to save
+ termsBase.getSession().save();
+ } catch (RepositoryException | IOException e) {
+ log.error("Cannot load terms '" + name + "': " + e.getMessage());
+ throw e;
+ }
+ }
+
+}
--- /dev/null
+package org.argeo.app.jcr;
+
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.app.api.EntityConstants;
+import org.argeo.app.api.EntityDefinition;
+import org.argeo.cms.jcr.CmsJcrUtils;
+import org.argeo.jcr.Jcr;
+import org.osgi.framework.BundleContext;
+
+/** An entity definition based on a JCR data structure. */
+public class JcrEntityDefinition implements EntityDefinition {
+ private Repository repository;
+
+ private String type;
+ private String defaultEditorId;
+
+ public void init(BundleContext bundleContext, Map<String, String> properties) throws RepositoryException {
+ Session adminSession = CmsJcrUtils.openDataAdminSession(repository, null);
+ try {
+ type = properties.get(EntityConstants.TYPE);
+ if (type == null)
+ throw new IllegalArgumentException("Entity type property " + EntityConstants.TYPE + " must be set.");
+ defaultEditorId = properties.get(EntityConstants.DEFAULT_EDITOR_ID);
+// String definitionPath = EntityNames.ENTITY_DEFINITIONS_PATH + '/' + type;
+// if (!adminSession.itemExists(definitionPath)) {
+// Node entityDefinition = JcrUtils.mkdirs(adminSession, definitionPath, EntityTypes.ENTITY_DEFINITION);
+//// entityDefinition.addMixin(EntityTypes.ENTITY_DEFINITION);
+// adminSession.save();
+// }
+ initJcr(adminSession);
+ } finally {
+ Jcr.logout(adminSession);
+ }
+ }
+
+ /** To be overridden in order to perform additional initialisations. */
+ protected void initJcr(Session adminSession) throws RepositoryException {
+
+ }
+
+ public void destroy(BundleContext bundleContext, Map<String, String> properties) throws RepositoryException {
+
+ }
+
+ @Override
+ public String getEditorId(Node entity) {
+ return defaultEditorId;
+ }
+
+ @Override
+ public String getType() {
+ return type;
+ }
+
+ protected Repository getRepository() {
+ return repository;
+ }
+
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+ public String toString() {
+ return "Entity Definition " + getType();
+ }
+
+}
--- /dev/null
+package org.argeo.app.jcr;
+
+import static org.argeo.app.core.SuiteUtils.USER_DEVICES_NODE_NAME;
+import static org.argeo.app.core.SuiteUtils.USER_SESSIONS_NODE_NAME;
+import static org.argeo.app.core.SuiteUtils.USER_STATE_NODE_NAME;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.security.Privilege;
+import javax.security.auth.x500.X500Principal;
+
+import org.argeo.api.acr.ldap.LdapAttr;
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.api.cms.CmsSession;
+import org.argeo.app.api.AppUserState;
+import org.argeo.app.api.EntityType;
+import org.argeo.app.core.SuiteUtils;
+import org.argeo.cms.RoleNameUtils;
+import org.argeo.jcr.JcrException;
+import org.argeo.jcr.JcrUtils;
+
+/** JCR utilities. */
+public class SuiteJcrUtils {
+ /** @deprecated Use {@link AppUserState} instead. */
+ @Deprecated
+ public static Node getOrCreateUserNode(Session adminSession, String userDn) {
+ try {
+ Node usersBase = adminSession.getNode(EntityType.user.basePath());
+ String uid = RoleNameUtils.getLastRdnValue(userDn);
+ Node userNode;
+ if (!usersBase.hasNode(uid)) {
+ userNode = usersBase.addNode(uid, NodeType.NT_UNSTRUCTURED);
+ userNode.addMixin(EntityType.user.get());
+ userNode.addMixin(NodeType.MIX_CREATED);
+ userNode.setProperty(LdapAttr.distinguishedName.get(), userDn.toString());
+ userNode.setProperty(LdapAttr.uid.get(), uid);
+ } else {
+ userNode = usersBase.getNode(uid);
+ }
+
+ if (!userNode.hasNode(USER_SESSIONS_NODE_NAME)) {
+ // Migrate existing user node
+ Node sessionsNode = userNode.addNode(USER_SESSIONS_NODE_NAME, NodeType.NT_UNSTRUCTURED);
+ oldSessions: for (NodeIterator nit = userNode.getNodes(); nit.hasNext();) {
+ Node child = nit.nextNode();
+ if (USER_SESSIONS_NODE_NAME.equals(child.getName()) || child.getName().startsWith("rep:")
+ || child.getName().startsWith("jcr:"))
+ continue oldSessions;
+ Node target = sessionsNode.addNode(child.getName());
+ JcrUtils.copy(child, target);
+ }
+
+ Node userStateNode = userNode.addNode(USER_STATE_NODE_NAME, NodeType.NT_UNSTRUCTURED);
+ Node userDevicesNode = userNode.addNode(USER_DEVICES_NODE_NAME, NodeType.NT_UNSTRUCTURED);
+
+ adminSession.save();
+// JackrabbitSecurityUtils.denyPrivilege(adminSession, userNode.getPath(), SuiteRole.coworker.dn(),
+// Privilege.JCR_READ);
+ JcrUtils.addPrivilege(adminSession, userNode.getPath(), new X500Principal(userDn.toString()).getName(),
+ Privilege.JCR_READ);
+ JcrUtils.addPrivilege(adminSession, userNode.getPath(), CmsConstants.ROLE_USER_ADMIN,
+ Privilege.JCR_ALL);
+
+ JcrUtils.addPrivilege(adminSession, userStateNode.getPath(), userDn, Privilege.JCR_ALL);
+ JcrUtils.addPrivilege(adminSession, userDevicesNode.getPath(), userDn, Privilege.JCR_ALL);
+ }
+ return userNode;
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot create user node for " + userDn, e);
+ }
+ }
+
+ /** @deprecated Use {@link AppUserState} instead. */
+ @Deprecated
+ public static Node getCmsSessionNode(Session session, CmsSession cmsSession) {
+ try {
+ return session.getNode(SuiteUtils.getUserNodePath(cmsSession.getUserDn()) + '/' + USER_SESSIONS_NODE_NAME + '/'
+ + cmsSession.getUuid().toString());
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot get session dir for " + cmsSession, e);
+ }
+ }
+
+ /** @deprecated Use {@link AppUserState} instead. */
+ @Deprecated
+ public static Node getOrCreateCmsSessionNode(Session adminSession, CmsSession cmsSession) {
+ try {
+ String userDn = cmsSession.getUserDn();
+ Node userNode = getOrCreateUserNode(adminSession, userDn);
+ Node sessionsNode = userNode.getNode(USER_SESSIONS_NODE_NAME);
+ String cmsSessionUuid = cmsSession.getUuid().toString();
+ Node cmsSessionNode;
+ if (!sessionsNode.hasNode(cmsSessionUuid)) {
+ cmsSessionNode = sessionsNode.addNode(cmsSessionUuid, NodeType.NT_UNSTRUCTURED);
+ cmsSessionNode.addMixin(NodeType.MIX_CREATED);
+ adminSession.save();
+ JcrUtils.addPrivilege(adminSession, cmsSessionNode.getPath(), cmsSession.getUserRole(),
+ Privilege.JCR_ALL);
+ } else {
+ cmsSessionNode = sessionsNode.getNode(cmsSessionUuid);
+ }
+ return cmsSessionNode;
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot create session dir for " + cmsSession, e);
+ }
+ }
+
+ /** singleton */
+ private SuiteJcrUtils() {
+ }
+}
--- /dev/null
+package org.argeo.app.jcr;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryManager;
+
+import org.apache.jackrabbit.util.ISO9075;
+import org.argeo.api.cms.CmsLog;
+
+/** Ease XPath generation for JCR requests */
+public class XPathUtils {
+ private final static CmsLog log = CmsLog.getLog(XPathUtils.class);
+
+ private final static String QUERY_XPATH = "xpath";
+
+ public static String descendantFrom(String parentPath) {
+ if (notEmpty(parentPath)) {
+ if ("/".equals(parentPath))
+ parentPath = "";
+ // Hardcoded dependency to Jackrabbit. Remove
+ String result = "/jcr:root" + ISO9075.encodePath(parentPath);
+ if (log.isTraceEnabled()) {
+ String result2 = "/jcr:root" + parentPath;
+ if (!result2.equals(result))
+ log.warn("Encoded Path " + result2 + " --> " + result);
+ }
+ return result;
+ } else
+ return "";
+ }
+
+ public static String localAnd(String... conditions) {
+ StringBuilder builder = new StringBuilder();
+ for (String condition : conditions) {
+ if (notEmpty(condition)) {
+ builder.append(" ").append(condition).append(" and ");
+ }
+ }
+ if (builder.length() > 3)
+ return builder.substring(0, builder.length() - 4);
+ else
+ return "";
+ }
+
+ public static String xPathNot(String condition) {
+ if (notEmpty(condition))
+ return "not(" + condition + ")";
+ else
+ return "";
+ }
+
+ public static String getFreeTextConstraint(String filter) throws RepositoryException {
+ StringBuilder builder = new StringBuilder();
+ if (notEmpty(filter)) {
+ String[] strs = filter.trim().split(" ");
+ for (String token : strs) {
+ builder.append("jcr:contains(.,'*" + encodeXPathStringValue(token) + "*') and ");
+ }
+ return builder.substring(0, builder.length() - 4);
+ }
+ return "";
+ }
+
+ public static String getPropertyContains(String propertyName, String filter) throws RepositoryException {
+ if (notEmpty(filter))
+ return "jcr:contains(@" + propertyName + ",'*" + encodeXPathStringValue(filter) + "*')";
+ return "";
+ }
+
+ private final static DateFormat jcrRefFormatter = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSS'+02:00'");
+
+ /**
+ * @param propertyName
+ * @param calendar the reference date
+ * @param lowerOrGreater "<", ">" TODO validate ">="
+ * @throws RepositoryException
+ */
+ public static String getPropertyDateComparaison(String propertyName, Calendar cal, String lowerOrGreater)
+ throws RepositoryException {
+ if (cal != null) {
+ String jcrDateStr = jcrRefFormatter.format(cal.getTime());
+
+ // jcrDateStr = "2015-08-03T05:00:03:000Z";
+ String result = "@" + propertyName + " " + lowerOrGreater + " xs:dateTime('" + jcrDateStr + "')";
+ return result;
+ }
+ return "";
+ }
+
+ public static String getPropertyEquals(String propertyName, String value) {
+ if (notEmpty(value))
+ return "@" + propertyName + "='" + encodeXPathStringValue(value) + "'";
+ return "";
+ }
+
+ public static String encodeXPathStringValue(String propertyValue) {
+ // TODO implement safer mechanism to escape invalid characters
+ // Also check why we have used this regex in ResourceSerrviceImpl l 474
+ // String cleanedKey = key.replaceAll("(?:')", "''");
+ String result = propertyValue.replaceAll("'", "''");
+ return result;
+ }
+
+ public static void andAppend(StringBuilder builder, String condition) {
+ if (notEmpty(condition)) {
+ builder.append(condition);
+ builder.append(" and ");
+ }
+ }
+
+ public static void appendOrderByProperties(StringBuilder builder, boolean ascending, String... propertyNames) {
+ if (propertyNames.length > 0) {
+ builder.append(" order by ");
+ for (String propName : propertyNames)
+ builder.append("@").append(propName).append(", ");
+ builder = builder.delete(builder.length() - 2, builder.length());
+ if (ascending)
+ builder.append(" ascending ");
+ else
+ builder.append(" descending ");
+ }
+ }
+
+ public static void appendAndPropStringCondition(StringBuilder builder, String propertyName, String filter)
+ throws RepositoryException {
+ if (notEmpty(filter)) {
+ andAppend(builder, getPropertyContains(propertyName, filter));
+ }
+ }
+
+ public static void appendAndNotPropStringCondition(StringBuilder builder, String propertyName, String filter)
+ throws RepositoryException {
+ if (notEmpty(filter)) {
+ String cond = getPropertyContains(propertyName, filter);
+ builder.append(xPathNot(cond));
+ builder.append(" and ");
+ }
+ }
+
+ public static Query createQuery(Session session, String queryString) throws RepositoryException {
+ QueryManager queryManager = session.getWorkspace().getQueryManager();
+ // Localise JCR properties for XPATH
+ queryString = localiseJcrItemNames(queryString);
+ return queryManager.createQuery(queryString, QUERY_XPATH);
+ }
+
+ private final static String NS_JCR = "\\{http://www.jcp.org/jcr/1.0\\}";
+ private final static String NS_NT = "\\{http://www.jcp.org/jcr/nt/1.0\\}";
+ private final static String NS_MIX = "\\{http://www.jcp.org/jcr/mix/1.0\\}";
+
+ /**
+ * Replace the generic namespace with the local "jcr:", "nt:", "mix:" values. It
+ * is a workaround that must be later cleaned
+ */
+ public static String localiseJcrItemNames(String name) {
+ name = name.replaceAll(NS_JCR, "jcr:");
+ name = name.replaceAll(NS_NT, "nt:");
+ name = name.replaceAll(NS_MIX, "mix:");
+ return name;
+ }
+
+ private static boolean notEmpty(String stringToTest) {
+ return !(stringToTest == null || "".equals(stringToTest.trim()));
+ }
+
+ /** Singleton. */
+ private XPathUtils() {
+
+ }
+}
--- /dev/null
+package org.argeo.app.jcr.docbook;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.jcr.ImportUUIDBehavior;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Templates;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.argeo.jcr.JcrException;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import net.sf.saxon.BasicTransformerFactory;
+import net.sf.saxon.TransformerFactoryImpl;
+
+/** Convert from DocBook v4 to DocBook v5, using the official XSL. */
+public class Dbk4Converter {
+ private final Templates templates;
+
+ public Dbk4Converter() {
+ try (InputStream in = getClass().getResourceAsStream("db4-upgrade.xsl")) {
+ Source xsl = new StreamSource(in);
+ TransformerFactory transformerFactory = new BasicTransformerFactory();
+// TransformerFactory transformerFactory = new TransformerFactoryImpl();
+ templates = transformerFactory.newTemplates(xsl);
+ } catch (IOException | TransformerConfigurationException e) {
+ throw new RuntimeException("Cannot initialise DocBook v4 converter", e);
+ }
+ }
+
+ public void importXml(Node baseNode, InputStream in) throws IOException {
+ try (ByteArrayOutputStream out = new ByteArrayOutputStream();) {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setXIncludeAware(true);
+ factory.setNamespaceAware(true);
+ DocumentBuilder docBuilder = factory.newDocumentBuilder();
+ Document doc = docBuilder.parse(new InputSource(in));
+ Source xmlInput = new DOMSource(doc);
+
+// ContentHandler contentHandler = baseNode.getSession().getImportContentHandler(baseNode.getPath(),
+// ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
+
+ Transformer transformer = templates.newTransformer();
+ Result xmlOutput = new StreamResult(out);
+ transformer.transform(xmlInput, xmlOutput);
+ try (InputStream dbk5in = new ByteArrayInputStream(out.toByteArray())) {
+ baseNode.getSession().importXML(baseNode.getPath(), dbk5in,
+ ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
+ }
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot import XML to " + baseNode, e);
+ } catch (TransformerException | SAXException | ParserConfigurationException e) {
+ throw new RuntimeException("Cannot import DocBook v4 to " + baseNode, e);
+ }
+
+ }
+
+ public static void main(String[] args) {
+ try {
+
+ Source xsl = new StreamSource(new File("/usr/share/xml/docbook5/stylesheet/upgrade/db4-upgrade.xsl"));
+ TransformerFactory transformerFactory = new TransformerFactoryImpl();
+ Templates templates = transformerFactory.newTemplates(xsl);
+
+ File inputDir = new File(args[0]);
+ File outputDir = new File(args[1]);
+
+ for (File inputFile : inputDir.listFiles()) {
+ Result xmlOutput = new StreamResult(new File(outputDir, inputFile.getName()));
+
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setXIncludeAware(true);
+ factory.setNamespaceAware(true);
+ DocumentBuilder docBuilder = factory.newDocumentBuilder();
+ Document doc = docBuilder.parse(inputFile);
+ Source xmlInput = new DOMSource(doc);
+ Transformer transformer = templates.newTransformer();
+ transformer.transform(xmlInput, xmlOutput);
+ }
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+}
--- /dev/null
+package org.argeo.app.jcr.docbook;
+
+import static org.argeo.app.docbook.DbkType.para;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import javax.jcr.ImportUUIDBehavior;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.app.api.EntityType;
+import org.argeo.app.docbook.DbkAttr;
+import org.argeo.app.docbook.DbkType;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrException;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.jcr.JcrxApi;
+
+/** JCR utilities around DocBook. */
+public class DbkJcrUtils {
+ private final static CmsLog log = CmsLog.getLog(DbkJcrUtils.class);
+
+ /** Get or add a DocBook element. */
+ public static Node getOrAddDbk(Node parent, DbkType child) {
+ try {
+ if (!parent.hasNode(child.get())) {
+ return addDbk(parent, child);
+ } else {
+ return parent.getNode(child.get());
+ }
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot get or add element " + child.get() + " to " + parent, e);
+ }
+ }
+
+ /** Add a DocBook element to this node. */
+ public static Node addDbk(Node parent, DbkType child) {
+ try {
+ Node node = parent.addNode(child.get(), child.get());
+ return node;
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot add element " + child.get() + " to " + parent, e);
+ }
+ }
+
+ /** Whether this DocBook element is of this type. */
+ public static boolean isDbk(Node node, DbkType type) {
+ return Jcr.getName(node).equals(type.get());
+ }
+
+ /** Whether this node is a DocBook type. */
+ public static boolean isDbk(Node node) {
+ String name = Jcr.getName(node);
+ for (DbkType type : DbkType.values()) {
+ if (name.equals(type.get()))
+ return true;
+ }
+ return false;
+ }
+
+ public static String getTitle(Node node) {
+ return JcrxApi.getXmlValue(node, DbkType.title.get());
+ }
+
+ public static void setTitle(Node node, String txt) {
+ Node titleNode = getOrAddDbk(node, DbkType.title);
+ JcrxApi.setXmlValue(titleNode, txt);
+ }
+
+ public static Node getMetadata(Node infoContainer) {
+ try {
+ if (!infoContainer.hasNode(DbkType.info.get()))
+ return null;
+ Node info = infoContainer.getNode(DbkType.info.get());
+ if (!info.hasNode(EntityType.local.get()))
+ return null;
+ return info.getNode(EntityType.local.get());
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot retrieve metadata from " + infoContainer, e);
+ }
+ }
+
+ public static Node getChildByRole(Node parent, String role) {
+ try {
+ NodeIterator baseSections = parent.getNodes();
+ while (baseSections.hasNext()) {
+ Node n = baseSections.nextNode();
+ String r = Jcr.get(n, DbkAttr.role.name());
+ if (r != null && r.equals(role))
+ return n;
+ }
+ return null;
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot get child from " + parent + " with role " + role, e);
+ }
+ }
+
+ public static Node addParagraph(Node node, String txt) {
+ Node p = addDbk(node, para);
+ JcrxApi.setXmlValue(p, txt);
+ return p;
+ }
+
+ /**
+ * Removes a paragraph if it empty. The sesison is not saved.
+ *
+ * @return true if the paragraph was empty and it was removed
+ */
+ public static boolean removeIfEmptyParagraph(Node node) {
+ try {
+ if (isDbk(node, DbkType.para)) {
+ NodeIterator nit = node.getNodes();
+ if (!nit.hasNext()) {
+ node.remove();
+ return true;
+ }
+ Node first = nit.nextNode();
+ if (nit.hasNext())
+ return false;
+ if (first.getName().equals(Jcr.JCR_XMLTEXT)) {
+ String str = Jcr.get(first, Jcr.JCR_XMLCHARACTERS);
+ if (str != null && str.trim().equals("")) {
+ node.remove();
+ return true;
+ }
+ } else {
+ return false;
+ }
+ }
+ return false;
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot remove possibly empty paragraph", e);
+ }
+ }
+
+ public static Node insertImageAfter(Node sibling) {
+ try {
+
+ Node parent = sibling.getParent();
+ Node mediaNode = addDbk(parent, DbkType.mediaobject);
+ // TODO optimise?
+ parent.orderBefore(mediaNode.getName() + "[" + mediaNode.getIndex() + "]",
+ sibling.getName() + "[" + sibling.getIndex() + "]");
+ parent.orderBefore(sibling.getName() + "[" + sibling.getIndex() + "]",
+ mediaNode.getName() + "[" + mediaNode.getIndex() + "]");
+
+ Node imageNode = addDbk(mediaNode, DbkType.imageobject);
+ Node imageDataNode = addDbk(imageNode, DbkType.imagedata);
+// Node infoNode = imageNode.addNode(DocBookTypes.INFO, DocBookTypes.INFO);
+// Node fileNode = JcrUtils.copyBytesAsFile(mediaFolder, EntityType.box.get(), new byte[0]);
+// fileNode.addMixin(EntityType.box.get());
+// fileNode.setProperty(EntityNames.SVG_WIDTH, 0);
+// fileNode.setProperty(EntityNames.SVG_LENGTH, 0);
+// fileNode.addMixin(NodeType.MIX_MIMETYPE);
+//
+// // we assume this is a folder next to the main DocBook document
+// // TODO make it more robust and generic
+// String fileRef = mediaNode.getName();
+// imageDataNode.setProperty(DocBookNames.DBK_FILEREF, fileRef);
+ return mediaNode;
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot insert empty image after " + sibling, e);
+ }
+ }
+
+ public static Node insertVideoAfter(Node sibling) {
+ try {
+
+ Node parent = sibling.getParent();
+ Node mediaNode = addDbk(parent, DbkType.mediaobject);
+ // TODO optimise?
+ parent.orderBefore(mediaNode.getName() + "[" + mediaNode.getIndex() + "]",
+ sibling.getName() + "[" + sibling.getIndex() + "]");
+ parent.orderBefore(sibling.getName() + "[" + sibling.getIndex() + "]",
+ mediaNode.getName() + "[" + mediaNode.getIndex() + "]");
+
+ Node videoNode = addDbk(mediaNode, DbkType.videoobject);
+ Node videoDataNode = addDbk(videoNode, DbkType.videodata);
+ return mediaNode;
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot insert empty image after " + sibling, e);
+ }
+ }
+
+ public static String getMediaFileref(Node node) {
+ try {
+ Node mediadata;
+ if (node.hasNode(DbkType.imageobject.get())) {
+ mediadata = node.getNode(DbkType.imageobject.get()).getNode(DbkType.imagedata.get());
+ } else if (node.hasNode(DbkType.videoobject.get())) {
+ mediadata = node.getNode(DbkType.videoobject.get()).getNode(DbkType.videodata.get());
+ } else {
+ throw new IllegalArgumentException("Fileref not found in " + node);
+ }
+
+ if (mediadata.hasProperty(DbkAttr.fileref.name())) {
+ return mediadata.getProperty(DbkAttr.fileref.name()).getString();
+ } else {
+ return null;
+ }
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot retrieve file ref from " + node, e);
+ }
+ }
+
+ public static void exportXml(Node node, OutputStream out) throws IOException {
+ try {
+ node.getSession().exportDocumentView(node.getPath(), out, false, false);
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot export " + node + " to XML", e);
+ }
+ }
+
+ public static void exportToFs(Node baseNode, DbkType type, Path directory) {
+ String fileName = Jcr.getName(baseNode) + ".dbk.xml";
+ Path filePath = directory.resolve(fileName);
+ Node docBookNode = Jcr.getNode(baseNode, type.get());
+ if (docBookNode == null)
+ throw new IllegalArgumentException("No " + type.get() + " under " + baseNode);
+ try {
+ Files.createDirectories(directory);
+ try (OutputStream out = Files.newOutputStream(filePath)) {
+ exportXml(docBookNode, out);
+ }
+ JcrUtils.copyFilesToFs(baseNode, directory, true);
+ if (log.isDebugEnabled())
+ log.debug("DocBook " + baseNode + " exported to " + filePath.toAbsolutePath());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static void importXml(Node baseNode, InputStream in) throws IOException {
+ try {
+ baseNode.getSession().importXML(baseNode.getPath(), in,
+ ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot import XML to " + baseNode, e);
+ }
+
+ }
+
+ /** Singleton. */
+ private DbkJcrUtils() {
+ }
+
+}
--- /dev/null
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:exsl="http://exslt.org/common"
+ xmlns:db = "http://docbook.org/ns/docbook"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ exclude-result-prefixes="exsl db"
+ version="1.0">
+
+<!--
+# ======================================================================
+# This file is part of DocBook V5.0CR5
+#
+# Copyright 2005 Norman Walsh, Sun Microsystems, Inc., and the
+# Organization for the Advancement of Structured Information
+# Standards (OASIS).
+#
+# Release: $Id: db4-upgrade.xsl 7660 2008-02-06 13:48:36Z nwalsh $
+#
+# Permission to use, copy, modify and distribute this stylesheet
+# and its accompanying documentation for any purpose and without fee
+# is hereby granted in perpetuity, provided that the above copyright
+# notice and this paragraph appear in all copies. The copyright
+# holders make no representation about the suitability of the schema
+# for any purpose. It is provided "as is" without expressed or implied
+# warranty.
+#
+# Please direct all questions, bug reports, or suggestions for changes
+# to the docbook@lists.oasis-open.org mailing list. For more
+# information, see http://www.oasis-open.org/docbook/.
+#
+# ======================================================================
+-->
+
+<xsl:variable name="version" select="'1.0'"/>
+
+<xsl:output method="xml" encoding="utf-8" indent="no" omit-xml-declaration="yes"/>
+
+<xsl:preserve-space elements="*"/>
+<xsl:param name="rootid">
+ <xsl:choose>
+ <xsl:when test="/*/@id">
+ <xsl:value-of select="/*/@id"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>UNKNOWN</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:param>
+
+<xsl:param name="defaultDate" select="''"/>
+
+<xsl:template match="/">
+ <xsl:variable name="converted">
+ <xsl:apply-templates/>
+ </xsl:variable>
+ <xsl:comment>
+ <xsl:text> Converted by db4-upgrade version </xsl:text>
+ <xsl:value-of select="$version"/>
+ <xsl:text> </xsl:text>
+ </xsl:comment>
+ <xsl:text> </xsl:text>
+ <xsl:apply-templates select="exsl:node-set($converted)/*" mode="addNS"/>
+</xsl:template>
+
+<xsl:template match="bookinfo|chapterinfo|articleinfo|artheader|appendixinfo
+ |blockinfo
+ |bibliographyinfo|glossaryinfo|indexinfo|setinfo
+ |setindexinfo
+ |sect1info|sect2info|sect3info|sect4info|sect5info
+ |sectioninfo
+ |refsect1info|refsect2info|refsect3info|refsectioninfo
+ |referenceinfo|partinfo"
+ priority="200">
+ <info>
+ <xsl:call-template name="copy.attributes"/>
+
+ <!-- titles can be inside or outside or both. fix that -->
+ <xsl:choose>
+ <xsl:when test="title and following-sibling::title">
+ <xsl:if test="title != following-sibling::title">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Check </xsl:text>
+ <xsl:value-of select="name(..)"/>
+ <xsl:text> title.</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:apply-templates select="title" mode="copy"/>
+ </xsl:when>
+ <xsl:when test="title">
+ <xsl:apply-templates select="title" mode="copy"/>
+ </xsl:when>
+ <xsl:when test="following-sibling::title">
+ <xsl:apply-templates select="following-sibling::title" mode="copy"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Check </xsl:text>
+ <xsl:value-of select="name(..)"/>
+ <xsl:text>: no title.</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="titleabbrev and following-sibling::titleabbrev">
+ <xsl:if test="titleabbrev != following-sibling::titleabbrev">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Check </xsl:text>
+ <xsl:value-of select="name(..)"/>
+ <xsl:text> titleabbrev.</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:apply-templates select="titleabbrev" mode="copy"/>
+ </xsl:when>
+ <xsl:when test="titleabbrev">
+ <xsl:apply-templates select="titleabbrev" mode="copy"/>
+ </xsl:when>
+ <xsl:when test="following-sibling::titleabbrev">
+ <xsl:apply-templates select="following-sibling::titleabbrev" mode="copy"/>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="subtitle and following-sibling::subtitle">
+ <xsl:if test="subtitle != following-sibling::subtitle">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Check </xsl:text>
+ <xsl:value-of select="name(..)"/>
+ <xsl:text> subtitle.</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:apply-templates select="subtitle" mode="copy"/>
+ </xsl:when>
+ <xsl:when test="subtitle">
+ <xsl:apply-templates select="subtitle" mode="copy"/>
+ </xsl:when>
+ <xsl:when test="following-sibling::subtitle">
+ <xsl:apply-templates select="following-sibling::subtitle" mode="copy"/>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:apply-templates/>
+ </info>
+</xsl:template>
+
+<xsl:template match="objectinfo|prefaceinfo|refsynopsisdivinfo
+ |screeninfo|sidebarinfo"
+ priority="200">
+ <info>
+ <xsl:call-template name="copy.attributes"/>
+
+ <!-- titles can be inside or outside or both. fix that -->
+ <xsl:choose>
+ <xsl:when test="title and following-sibling::title">
+ <xsl:if test="title != following-sibling::title">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Check </xsl:text>
+ <xsl:value-of select="name(..)"/>
+ <xsl:text> title.</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:apply-templates select="title" mode="copy"/>
+ </xsl:when>
+ <xsl:when test="title">
+ <xsl:apply-templates select="title" mode="copy"/>
+ </xsl:when>
+ <xsl:when test="following-sibling::title">
+ <xsl:apply-templates select="following-sibling::title" mode="copy"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <!-- it's ok if there's no title on these -->
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="titleabbrev and following-sibling::titleabbrev">
+ <xsl:if test="titleabbrev != following-sibling::titleabbrev">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Check </xsl:text>
+ <xsl:value-of select="name(..)"/>
+ <xsl:text> titleabbrev.</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:apply-templates select="titleabbrev" mode="copy"/>
+ </xsl:when>
+ <xsl:when test="titleabbrev">
+ <xsl:apply-templates select="titleabbrev" mode="copy"/>
+ </xsl:when>
+ <xsl:when test="following-sibling::titleabbrev">
+ <xsl:apply-templates select="following-sibling::titleabbrev" mode="copy"/>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="subtitle and following-sibling::subtitle">
+ <xsl:if test="subtitle != following-sibling::subtitle">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Check </xsl:text>
+ <xsl:value-of select="name(..)"/>
+ <xsl:text> subtitle.</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:apply-templates select="subtitle" mode="copy"/>
+ </xsl:when>
+ <xsl:when test="subtitle">
+ <xsl:apply-templates select="subtitle" mode="copy"/>
+ </xsl:when>
+ <xsl:when test="following-sibling::subtitle">
+ <xsl:apply-templates select="following-sibling::subtitle" mode="copy"/>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:apply-templates/>
+ </info>
+</xsl:template>
+
+<xsl:template match="refentryinfo"
+ priority="200">
+ <info>
+ <xsl:call-template name="copy.attributes"/>
+
+ <!-- titles can be inside or outside or both. fix that -->
+ <xsl:if test="title">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Discarding title from refentryinfo!</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+
+ <xsl:if test="titleabbrev">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Discarding titleabbrev from refentryinfo!</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+
+ <xsl:if test="subtitle">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Discarding subtitle from refentryinfo!</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+
+ <xsl:apply-templates/>
+ </info>
+</xsl:template>
+
+<xsl:template match="refmiscinfo"
+ priority="200">
+ <refmiscinfo>
+ <xsl:call-template name="copy.attributes">
+ <xsl:with-param name="suppress" select="'class'"/>
+ </xsl:call-template>
+ <xsl:if test="@class">
+ <xsl:choose>
+ <xsl:when test="@class = 'source'
+ or @class = 'version'
+ or @class = 'manual'
+ or @class = 'sectdesc'
+ or @class = 'software'">
+ <xsl:attribute name="class">
+ <xsl:value-of select="@class"/>
+ </xsl:attribute>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:attribute name="class">
+ <xsl:value-of select="'other'"/>
+ </xsl:attribute>
+ <xsl:attribute name="otherclass">
+ <xsl:value-of select="@class"/>
+ </xsl:attribute>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:if>
+ <xsl:apply-templates/>
+ </refmiscinfo>
+</xsl:template>
+
+<xsl:template match="corpauthor" priority="200">
+ <author>
+ <xsl:call-template name="copy.attributes"/>
+ <orgname>
+ <xsl:apply-templates/>
+ </orgname>
+ </author>
+</xsl:template>
+
+<xsl:template match="corpname" priority="200">
+ <orgname>
+ <xsl:call-template name="copy.attributes"/>
+ <xsl:apply-templates/>
+ </orgname>
+</xsl:template>
+
+<xsl:template match="author[not(personname)]|editor[not(personname)]|othercredit[not(personname)]" priority="200">
+ <xsl:copy>
+ <xsl:call-template name="copy.attributes"/>
+ <personname>
+ <xsl:apply-templates select="honorific|firstname|surname|othername|lineage"/>
+ </personname>
+ <xsl:apply-templates select="*[not(self::honorific|self::firstname|self::surname
+ |self::othername|self::lineage)]"/>
+ </xsl:copy>
+</xsl:template>
+
+<xsl:template match="address|programlisting|screen|funcsynopsisinfo
+ |classsynopsisinfo|literallayout" priority="200">
+ <xsl:copy>
+ <xsl:call-template name="copy.attributes">
+ <xsl:with-param name="suppress" select="'format'"/>
+ </xsl:call-template>
+ <xsl:apply-templates/>
+ </xsl:copy>
+</xsl:template>
+
+<xsl:template match="productname[@class]" priority="200">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Dropping class attribute from productname</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+ <xsl:copy>
+ <xsl:call-template name="copy.attributes">
+ <xsl:with-param name="suppress" select="'class'"/>
+ </xsl:call-template>
+ <xsl:apply-templates/>
+ </xsl:copy>
+</xsl:template>
+
+<xsl:template match="dedication|preface|chapter|appendix|part|partintro
+ |article|bibliography|glossary|glossdiv|index
+ |reference[not(referenceinfo)]
+ |book" priority="200">
+ <xsl:choose>
+ <xsl:when test="not(dedicationinfo|prefaceinfo|chapterinfo
+ |appendixinfo|partinfo
+ |articleinfo|artheader|bibliographyinfo
+ |glossaryinfo|indexinfo
+ |bookinfo)">
+ <xsl:copy>
+ <xsl:call-template name="copy.attributes"/>
+ <xsl:if test="title|subtitle|titleabbrev">
+ <info>
+ <xsl:apply-templates select="title" mode="copy"/>
+ <xsl:apply-templates select="titleabbrev" mode="copy"/>
+ <xsl:apply-templates select="subtitle" mode="copy"/>
+ <xsl:apply-templates select="abstract" mode="copy"/>
+ </info>
+ </xsl:if>
+ <xsl:apply-templates/>
+ </xsl:copy>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:copy>
+ <xsl:call-template name="copy.attributes"/>
+ <xsl:apply-templates/>
+ </xsl:copy>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template match="formalpara|figure|table[tgroup]|example|blockquote
+ |caution|important|note|warning|tip
+ |bibliodiv|glossarydiv|indexdiv
+ |orderedlist|itemizedlist|variablelist|procedure
+ |task|tasksummary|taskprerequisites|taskrelated
+ |sidebar"
+ priority="200">
+ <xsl:choose>
+ <xsl:when test="blockinfo">
+ <xsl:copy>
+ <xsl:call-template name="copy.attributes"/>
+ <xsl:apply-templates/>
+ </xsl:copy>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:copy>
+ <xsl:call-template name="copy.attributes"/>
+
+ <xsl:if test="title|titleabbrev|subtitle">
+ <info>
+ <xsl:apply-templates select="title" mode="copy"/>
+ <xsl:apply-templates select="titleabbrev" mode="copy"/>
+ <xsl:apply-templates select="subtitle" mode="copy"/>
+ </info>
+ </xsl:if>
+
+ <xsl:apply-templates/>
+ </xsl:copy>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template match="equation" priority="200">
+ <xsl:choose>
+ <xsl:when test="not(title)">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param
+ name="message"
+ >Convert equation without title to informal equation.</xsl:with-param>
+ </xsl:call-template>
+ <informalequation>
+ <xsl:call-template name="copy.attributes"/>
+ <xsl:apply-templates/>
+ </informalequation>
+ </xsl:when>
+ <xsl:when test="blockinfo">
+ <xsl:copy>
+ <xsl:call-template name="copy.attributes"/>
+ <xsl:apply-templates/>
+ </xsl:copy>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:copy>
+ <xsl:call-template name="copy.attributes"/>
+ <info>
+ <xsl:apply-templates select="title" mode="copy"/>
+ <xsl:apply-templates select="titleabbrev" mode="copy"/>
+ <xsl:apply-templates select="subtitle" mode="copy"/>
+ </info>
+ <xsl:apply-templates/>
+ </xsl:copy>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template match="sect1|sect2|sect3|sect4|sect5|section"
+ priority="200">
+ <section>
+ <xsl:call-template name="copy.attributes"/>
+
+ <xsl:if test="not(sect1info|sect2info|sect3info|sect4info|sect5info|sectioninfo)">
+ <info>
+ <xsl:apply-templates select="title" mode="copy"/>
+ <xsl:apply-templates select="titleabbrev" mode="copy"/>
+ <xsl:apply-templates select="subtitle" mode="copy"/>
+ <xsl:apply-templates select="abstract" mode="copy"/>
+ </info>
+ </xsl:if>
+ <xsl:apply-templates/>
+ </section>
+</xsl:template>
+
+<xsl:template match="simplesect"
+ priority="200">
+ <simplesect>
+ <xsl:call-template name="copy.attributes"/>
+ <info>
+ <xsl:apply-templates select="title" mode="copy"/>
+ <xsl:apply-templates select="titleabbrev" mode="copy"/>
+ <xsl:apply-templates select="subtitle" mode="copy"/>
+ <xsl:apply-templates select="abstract" mode="copy"/>
+ </info>
+ <xsl:apply-templates/>
+ </simplesect>
+</xsl:template>
+
+<xsl:template match="refsect1|refsect2|refsect3|refsection" priority="200">
+ <refsection>
+ <xsl:call-template name="copy.attributes"/>
+
+ <xsl:if test="not(refsect1info|refsect2info|refsect3info|refsectioninfo)">
+ <info>
+ <xsl:apply-templates select="title" mode="copy"/>
+ <xsl:apply-templates select="titleabbrev" mode="copy"/>
+ <xsl:apply-templates select="subtitle" mode="copy"/>
+ <xsl:apply-templates select="abstract" mode="copy"/>
+ </info>
+ </xsl:if>
+ <xsl:apply-templates/>
+ </refsection>
+</xsl:template>
+
+<xsl:template match="imagedata|videodata|audiodata|textdata" priority="200">
+ <xsl:copy>
+ <xsl:call-template name="copy.attributes">
+ <xsl:with-param name="suppress" select="'srccredit'"/>
+ </xsl:call-template>
+ <xsl:if test="@srccredit">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Check conversion of srccredit </xsl:text>
+ <xsl:text>(othercredit="srccredit").</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+ <info>
+ <othercredit class="other" otherclass="srccredit">
+ <orgname>???</orgname>
+ <contrib>
+ <xsl:value-of select="@srccredit"/>
+ </contrib>
+ </othercredit>
+ </info>
+ </xsl:if>
+ </xsl:copy>
+</xsl:template>
+
+<xsl:template match="sgmltag" priority="200">
+ <tag>
+ <xsl:call-template name="copy.attributes"/>
+ <xsl:if test="@class = 'sgmlcomment'">
+ <xsl:attribute name="class">comment</xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates/>
+ </tag>
+</xsl:template>
+
+<xsl:template match="inlinegraphic[@format='linespecific']" priority="210">
+ <textobject>
+ <textdata>
+ <xsl:call-template name="copy.attributes"/>
+ </textdata>
+ </textobject>
+</xsl:template>
+
+<xsl:template match="inlinegraphic" priority="200">
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata>
+ <xsl:call-template name="copy.attributes"/>
+ </imagedata>
+ </imageobject>
+ </inlinemediaobject>
+</xsl:template>
+
+<xsl:template match="graphic[@format='linespecific']" priority="210">
+ <mediaobject>
+ <textobject>
+ <textdata>
+ <xsl:call-template name="copy.attributes"/>
+ </textdata>
+ </textobject>
+ </mediaobject>
+</xsl:template>
+
+<xsl:template match="graphic" priority="200">
+ <mediaobject>
+ <imageobject>
+ <imagedata>
+ <xsl:call-template name="copy.attributes"/>
+ </imagedata>
+ </imageobject>
+ </mediaobject>
+</xsl:template>
+
+<xsl:template match="pubsnumber" priority="200">
+ <biblioid class="pubsnumber">
+ <xsl:call-template name="copy.attributes"/>
+ <xsl:apply-templates/>
+ </biblioid>
+</xsl:template>
+
+<xsl:template match="invpartnumber" priority="200">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Converting invpartnumber to biblioid otherclass="invpartnumber".</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+ <biblioid class="other" otherclass="invpartnumber">
+ <xsl:call-template name="copy.attributes"/>
+ <xsl:apply-templates/>
+ </biblioid>
+</xsl:template>
+
+<xsl:template match="contractsponsor" priority="200">
+ <xsl:variable name="contractnum"
+ select="preceding-sibling::contractnum|following-sibling::contractnum"/>
+
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Converting contractsponsor to othercredit="contractsponsor".</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+
+ <othercredit class="other" otherclass="contractsponsor">
+ <orgname>
+ <xsl:call-template name="copy.attributes"/>
+ <xsl:apply-templates/>
+ </orgname>
+ <xsl:for-each select="$contractnum">
+ <contrib role="contractnum">
+ <xsl:apply-templates select="node()"/>
+ </contrib>
+ </xsl:for-each>
+ </othercredit>
+</xsl:template>
+
+<xsl:template match="contractnum" priority="200">
+ <xsl:if test="not(preceding-sibling::contractsponsor
+ |following-sibling::contractsponsor)
+ and not(preceding-sibling::contractnum)">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Converting contractnum to othercredit="contractnum".</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+
+ <othercredit class="other" otherclass="contractnum">
+ <orgname>???</orgname>
+ <xsl:for-each select="self::contractnum
+ |preceding-sibling::contractnum
+ |following-sibling::contractnum">
+ <contrib>
+ <xsl:apply-templates select="node()"/>
+ </contrib>
+ </xsl:for-each>
+ </othercredit>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template match="isbn|issn" priority="200">
+ <biblioid class="{local-name(.)}">
+ <xsl:call-template name="copy.attributes"/>
+ <xsl:apply-templates/>
+ </biblioid>
+</xsl:template>
+
+<xsl:template match="biblioid[count(*) = 1
+ and ulink
+ and normalize-space(text()) = '']" priority="200">
+ <biblioid xlink:href="{ulink/@url}">
+ <xsl:call-template name="copy.attributes"/>
+ <xsl:apply-templates select="ulink/node()"/>
+ </biblioid>
+</xsl:template>
+
+<xsl:template match="authorblurb" priority="200">
+ <personblurb>
+ <xsl:call-template name="copy.attributes"/>
+ <xsl:apply-templates/>
+ </personblurb>
+</xsl:template>
+
+<xsl:template match="collabname" priority="200">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Check conversion of collabname </xsl:text>
+ <xsl:text>(orgname role="collabname").</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+ <orgname role="collabname">
+ <xsl:call-template name="copy.attributes"/>
+ <xsl:apply-templates/>
+ </orgname>
+</xsl:template>
+
+<xsl:template match="modespec" priority="200">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Discarding modespec (</xsl:text>
+ <xsl:value-of select="."/>
+ <xsl:text>).</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+</xsl:template>
+
+<xsl:template match="mediaobjectco" priority="200">
+ <mediaobject>
+ <xsl:copy-of select="@*"/>
+ <xsl:apply-templates/>
+ </mediaobject>
+</xsl:template>
+
+<xsl:template match="remark" priority="200">
+ <!-- get rid of any embedded markup -->
+ <remark>
+ <xsl:copy-of select="@*"/>
+ <xsl:value-of select="."/>
+ </remark>
+</xsl:template>
+
+<xsl:template match="biblioentry/title
+ |bibliomset/title
+ |biblioset/title
+ |bibliomixed/title" priority="400">
+ <citetitle>
+ <xsl:copy-of select="@*"/>
+ <xsl:apply-templates/>
+ </citetitle>
+</xsl:template>
+
+<xsl:template match="biblioentry/titleabbrev|biblioentry/subtitle
+ |bibliomset/titleabbrev|bibliomset/subtitle
+ |biblioset/titleabbrev|biblioset/subtitle
+ |bibliomixed/titleabbrev|bibliomixed/subtitle"
+ priority="400">
+ <xsl:copy>
+ <xsl:copy-of select="@*"/>
+ <xsl:apply-templates/>
+ </xsl:copy>
+</xsl:template>
+
+<xsl:template match="biblioentry/contrib
+ |bibliomset/contrib
+ |bibliomixed/contrib" priority="200">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Check conversion of contrib </xsl:text>
+ <xsl:text>(othercontrib="contrib").</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+ <othercredit class="other" otherclass="contrib">
+ <orgname>???</orgname>
+ <contrib>
+ <xsl:call-template name="copy.attributes"/>
+ <xsl:apply-templates/>
+ </contrib>
+ </othercredit>
+</xsl:template>
+
+<xsl:template match="link" priority="200">
+ <xsl:copy>
+ <xsl:call-template name="copy.attributes"/>
+ <xsl:apply-templates/>
+ </xsl:copy>
+</xsl:template>
+
+<xsl:template match="ulink" priority="200">
+ <xsl:choose>
+ <xsl:when test="node()">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Converting ulink to link.</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+
+ <link xlink:href="{@url}">
+ <xsl:call-template name="copy.attributes">
+ <xsl:with-param name="suppress" select="'url'"/>
+ </xsl:call-template>
+ <xsl:apply-templates/>
+ </link>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Converting ulink to uri.</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+
+ <uri xlink:href="{@url}">
+ <xsl:call-template name="copy.attributes">
+ <xsl:with-param name="suppress" select="'url'"/>
+ </xsl:call-template>
+ <xsl:value-of select="@url"/>
+ </uri>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template match="olink" priority="200">
+ <xsl:if test="@linkmode">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Discarding linkmode on olink.</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+
+ <xsl:choose>
+ <xsl:when test="@targetdocent">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Converting olink targetdocent to targetdoc.</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+
+ <olink targetdoc="{unparsed-entity-uri(@targetdocent)}">
+ <xsl:for-each select="@*">
+ <xsl:if test="name(.) != 'targetdocent'
+ and name(.) != 'linkmode'">
+ <xsl:copy/>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:apply-templates/>
+ </olink>
+ </xsl:when>
+ <xsl:otherwise>
+ <olink>
+ <xsl:for-each select="@*">
+ <xsl:if test="name(.) != 'linkmode'">
+ <xsl:copy/>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:apply-templates/>
+ </olink>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template match="biblioentry/firstname
+ |biblioentry/surname
+ |biblioentry/othername
+ |biblioentry/lineage
+ |biblioentry/honorific
+ |bibliomset/firstname
+ |bibliomset/surname
+ |bibliomset/othername
+ |bibliomset/lineage
+ |bibliomset/honorific" priority="200">
+ <xsl:choose>
+ <xsl:when test="preceding-sibling::firstname
+ |preceding-sibling::surname
+ |preceding-sibling::othername
+ |preceding-sibling::lineage
+ |preceding-sibling::honorific">
+ <!-- nop -->
+ </xsl:when>
+ <xsl:otherwise>
+ <personname>
+ <xsl:apply-templates select="../firstname
+ |../surname
+ |../othername
+ |../lineage
+ |../honorific" mode="copy"/>
+ </personname>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template match="areaset" priority="200">
+ <xsl:copy>
+ <xsl:call-template name="copy.attributes">
+ <xsl:with-param name="suppress" select="'coords'"/>
+ </xsl:call-template>
+ <xsl:apply-templates/>
+ </xsl:copy>
+</xsl:template>
+
+<xsl:template match="date|pubdate" priority="200">
+ <xsl:variable name="rp1" select="substring-before(normalize-space(.), ' ')"/>
+ <xsl:variable name="rp2"
+ select="substring-before(substring-after(normalize-space(.), ' '),
+ ' ')"/>
+ <xsl:variable name="rp3"
+ select="substring-after(substring-after(normalize-space(.), ' '), ' ')"/>
+
+ <xsl:variable name="p1">
+ <xsl:choose>
+ <xsl:when test="contains($rp1, ',')">
+ <xsl:value-of select="substring-before($rp1, ',')"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$rp1"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:variable name="p2">
+ <xsl:choose>
+ <xsl:when test="contains($rp2, ',')">
+ <xsl:value-of select="substring-before($rp2, ',')"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$rp2"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:variable name="p3">
+ <xsl:choose>
+ <xsl:when test="contains($rp3, ',')">
+ <xsl:value-of select="substring-before($rp3, ',')"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$rp3"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:variable name="date">
+ <xsl:choose>
+ <xsl:when test="string($p1+1) != 'NaN' and string($p3+1) != 'NaN'">
+ <xsl:choose>
+ <xsl:when test="$p2 = 'Jan' or $p2 = 'January'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-01-</xsl:text>
+ <xsl:number value="$p1" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p2 = 'Feb' or $p2 = 'February'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-02-</xsl:text>
+ <xsl:number value="$p1" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p2 = 'Mar' or $p2 = 'March'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-03-</xsl:text>
+ <xsl:number value="$p1" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p2 = 'Apr' or $p2 = 'April'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-04-</xsl:text>
+ <xsl:number value="$p1" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p2 = 'May'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-05-</xsl:text>
+ <xsl:number value="$p1" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p2 = 'Jun' or $p2 = 'June'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-06-</xsl:text>
+ <xsl:number value="$p1" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p2 = 'Jul' or $p2 = 'July'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-07-</xsl:text>
+ <xsl:number value="$p1" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p2 = 'Aug' or $p2 = 'August'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-08-</xsl:text>
+ <xsl:number value="$p1" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p2 = 'Sep' or $p2 = 'September'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-09-</xsl:text>
+ <xsl:number value="$p1" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p2 = 'Oct' or $p2 = 'October'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-10-</xsl:text>
+ <xsl:number value="$p1" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p2 = 'Nov' or $p2 = 'November'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-11-</xsl:text>
+ <xsl:number value="$p1" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p2 = 'Dec' or $p2 = 'December'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-12-</xsl:text>
+ <xsl:number value="$p1" format="01"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:when test="string($p2+1) != 'NaN' and string($p3+1) != 'NaN'">
+ <xsl:choose>
+ <xsl:when test="$p1 = 'Jan' or $p1 = 'January'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-01-</xsl:text>
+ <xsl:number value="$p2" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p1 = 'Feb' or $p1 = 'February'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-02-</xsl:text>
+ <xsl:number value="$p2" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p1 = 'Mar' or $p1 = 'March'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-03-</xsl:text>
+ <xsl:number value="$p2" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p1 = 'Apr' or $p1 = 'April'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-04-</xsl:text>
+ <xsl:number value="$p2" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p1 = 'May'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-05-</xsl:text>
+ <xsl:number value="$p2" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p1 = 'Jun' or $p1 = 'June'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-06-</xsl:text>
+ <xsl:number value="$p2" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p1 = 'Jul' or $p1 = 'July'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-07-</xsl:text>
+ <xsl:number value="$p2" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p1 = 'Aug' or $p1 = 'August'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-08-</xsl:text>
+ <xsl:number value="$p2" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p1 = 'Sep' or $p1 = 'September'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-09-</xsl:text>
+ <xsl:number value="$p2" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p1 = 'Oct' or $p1 = 'October'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-10-</xsl:text>
+ <xsl:number value="$p2" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p1 = 'Nov' or $p1 = 'November'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-11-</xsl:text>
+ <xsl:number value="$p2" format="01"/>
+ </xsl:when>
+ <xsl:when test="$p1 = 'Dec' or $p1 = 'December'">
+ <xsl:number value="$p3" format="0001"/>
+ <xsl:text>-12-</xsl:text>
+ <xsl:number value="$p2" format="01"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:choose>
+ <xsl:when test="normalize-space($date) != normalize-space(.)">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Converted </xsl:text>
+ <xsl:value-of select="normalize-space(.)"/>
+ <xsl:text> into </xsl:text>
+ <xsl:value-of select="$date"/>
+ <xsl:text> for </xsl:text>
+ <xsl:value-of select="name(.)"/>
+ </xsl:with-param>
+ </xsl:call-template>
+
+ <xsl:copy>
+ <xsl:copy-of select="@*"/>
+ <xsl:value-of select="$date"/>
+ </xsl:copy>
+ </xsl:when>
+
+ <xsl:when test="$defaultDate != ''">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Unparseable date: </xsl:text>
+ <xsl:value-of select="normalize-space(.)"/>
+ <xsl:text> in </xsl:text>
+ <xsl:value-of select="name(.)"/>
+ <xsl:text> (Using default: </xsl:text>
+ <xsl:value-of select="$defaultDate"/>
+ <xsl:text>)</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+
+ <xsl:copy>
+ <xsl:copy-of select="@*"/>
+ <xsl:copy-of select="$defaultDate"/>
+ <xsl:comment>
+ <xsl:value-of select="."/>
+ </xsl:comment>
+ </xsl:copy>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <!-- these don't really matter anymore
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Unparseable date: </xsl:text>
+ <xsl:value-of select="normalize-space(.)"/>
+ <xsl:text> in </xsl:text>
+ <xsl:value-of select="name(.)"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ -->
+ <xsl:copy>
+ <xsl:copy-of select="@*"/>
+ <xsl:apply-templates/>
+ </xsl:copy>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template match="title|subtitle|titleabbrev" priority="300">
+ <!-- nop -->
+</xsl:template>
+
+<xsl:template match="abstract" priority="300">
+ <xsl:if test="not(contains(name(parent::*),'info'))">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Check abstract; moved into info correctly?</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template match="indexterm">
+ <!-- don't copy the defaulted significance='normal' attribute -->
+ <indexterm>
+ <xsl:call-template name="copy.attributes">
+ <xsl:with-param name="suppress">
+ <xsl:if test="@significance = 'normal'">significance</xsl:if>
+ </xsl:with-param>
+ </xsl:call-template>
+ <xsl:apply-templates/>
+ </indexterm>
+</xsl:template>
+
+<xsl:template match="ackno" priority="200">
+ <acknowledgements>
+ <xsl:copy-of select="@*"/>
+ <para>
+ <xsl:apply-templates/>
+ </para>
+ </acknowledgements>
+</xsl:template>
+
+<xsl:template match="lot|lotentry|tocback|tocchap|tocfront|toclevel1|
+ toclevel2|toclevel3|toclevel4|toclevel5|tocpart" priority="200">
+ <tocdiv>
+ <xsl:copy-of select="@*"/>
+ <xsl:apply-templates/>
+ </tocdiv>
+</xsl:template>
+
+<xsl:template match="action" priority="200">
+ <phrase remap="action">
+ <xsl:call-template name="copy.attributes"/>
+ <xsl:apply-templates/>
+ </phrase>
+</xsl:template>
+
+<xsl:template match="beginpage" priority="200">
+ <xsl:comment> beginpage pagenum=<xsl:value-of select="@pagenum"/> </xsl:comment>
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Replacing beginpage with comment</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+</xsl:template>
+
+<xsl:template match="structname|structfield" priority="200">
+ <varname remap="{local-name(.)}">
+ <xsl:call-template name="copy.attributes"/>
+ <xsl:apply-templates/>
+ </varname>
+</xsl:template>
+
+<!-- ====================================================================== -->
+
+<!-- 6 Feb 2008, ndw changed mode=copy so that it only copies the first level,
+ then it switches back to "normal" mode so that other rewriting templates
+ catch embedded fixes -->
+
+<!--
+<xsl:template match="ulink" priority="200" mode="copy">
+ <xsl:choose>
+ <xsl:when test="node()">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Converting ulink to phrase.</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+
+ <phrase xlink:href="{@url}">
+ <xsl:call-template name="copy.attributes">
+ <xsl:with-param name="suppress" select="'url'"/>
+ </xsl:call-template>
+ <xsl:apply-templates/>
+ </phrase>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Converting ulink to uri.</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+
+ <uri xlink:href="{@url}">
+ <xsl:call-template name="copy.attributes">
+ <xsl:with-param name="suppress" select="'url'"/>
+ </xsl:call-template>
+ <xsl:value-of select="@url"/>
+ </uri>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template match="sgmltag" priority="200" mode="copy">
+ <tag>
+ <xsl:call-template name="copy.attributes"/>
+ <xsl:apply-templates/>
+ </tag>
+</xsl:template>
+-->
+
+<xsl:template match="*" mode="copy">
+ <xsl:copy>
+ <xsl:call-template name="copy.attributes"/>
+ <xsl:apply-templates/>
+ </xsl:copy>
+</xsl:template>
+
+<!--
+<xsl:template match="comment()|processing-instruction()|text()" mode="copy">
+ <xsl:copy/>
+</xsl:template>
+-->
+
+<!-- ====================================================================== -->
+
+<xsl:template match="*">
+ <xsl:copy>
+ <xsl:call-template name="copy.attributes"/>
+ <xsl:apply-templates/>
+ </xsl:copy>
+</xsl:template>
+
+<xsl:template match="comment()|processing-instruction()|text()">
+ <xsl:copy/>
+</xsl:template>
+
+<!-- ====================================================================== -->
+
+<xsl:template name="copy.attributes">
+ <xsl:param name="src" select="."/>
+ <xsl:param name="suppress" select="''"/>
+
+ <xsl:for-each select="$src/@*">
+ <xsl:choose>
+ <xsl:when test="local-name(.) = 'moreinfo'">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Discarding moreinfo on </xsl:text>
+ <xsl:value-of select="local-name($src)"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="local-name(.) = 'lang'">
+ <xsl:attribute name="xml:lang">
+ <xsl:value-of select="."/>
+ </xsl:attribute>
+ </xsl:when>
+ <xsl:when test="local-name(.) = 'id'">
+ <xsl:attribute name="xml:id">
+ <xsl:value-of select="."/>
+ </xsl:attribute>
+ </xsl:when>
+ <xsl:when test="$suppress = local-name(.)"/>
+ <xsl:when test="local-name(.) = 'float'">
+ <xsl:choose>
+ <xsl:when test=". = '1'">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Discarding float on </xsl:text>
+ <xsl:value-of select="local-name($src)"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ <xsl:if test="not($src/@floatstyle)">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Adding floatstyle='normal' on </xsl:text>
+ <xsl:value-of select="local-name($src)"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ <xsl:attribute name="floatstyle">
+ <xsl:text>normal</xsl:text>
+ </xsl:attribute>
+ </xsl:if>
+ </xsl:when>
+ <xsl:when test=". = '0'">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Discarding float on </xsl:text>
+ <xsl:value-of select="local-name($src)"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Discarding float on </xsl:text>
+ <xsl:value-of select="local-name($src)"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ <xsl:if test="not($src/@floatstyle)">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Adding floatstyle='</xsl:text>
+ <xsl:value-of select="."/>
+ <xsl:text>' on </xsl:text>
+ <xsl:value-of select="local-name($src)"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ <xsl:attribute name="floatstyle">
+ <xsl:value-of select="."/>
+ </xsl:attribute>
+ </xsl:if>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:when test="local-name(.) = 'entityref'">
+ <xsl:attribute name="fileref">
+ <xsl:value-of select="unparsed-entity-uri(@entityref)"/>
+ </xsl:attribute>
+ </xsl:when>
+
+ <xsl:when test="local-name($src) = 'simplemsgentry'
+ and local-name(.) = 'audience'">
+ <xsl:attribute name="msgaud">
+ <xsl:value-of select="."/>
+ </xsl:attribute>
+ </xsl:when>
+ <xsl:when test="local-name($src) = 'simplemsgentry'
+ and local-name(.) = 'origin'">
+ <xsl:attribute name="msgorig">
+ <xsl:value-of select="."/>
+ </xsl:attribute>
+ </xsl:when>
+ <xsl:when test="local-name($src) = 'simplemsgentry'
+ and local-name(.) = 'level'">
+ <xsl:attribute name="msglevel">
+ <xsl:value-of select="."/>
+ </xsl:attribute>
+ </xsl:when>
+
+ <!-- * for upgrading XSL litprog params documentation -->
+ <xsl:when test="local-name($src) = 'refmiscinfo'
+ and local-name(.) = 'role'
+ and . = 'type'
+ ">
+ <xsl:call-template name="emit-message">
+ <xsl:with-param name="message">
+ <xsl:text>Converting refmiscinfo@role=type to </xsl:text>
+ <xsl:text>@class=other,otherclass=type</xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+ <xsl:attribute name="class">other</xsl:attribute>
+ <xsl:attribute name="otherclass">type</xsl:attribute>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:copy/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+</xsl:template>
+
+<!-- ====================================================================== -->
+
+<xsl:template match="*" mode="addNS">
+ <xsl:choose>
+ <xsl:when test="namespace-uri(.) = ''">
+ <xsl:element name="{local-name(.)}"
+ namespace="http://docbook.org/ns/docbook">
+ <xsl:if test="not(parent::*)">
+ <xsl:attribute name="version">5.0</xsl:attribute>
+ </xsl:if>
+ <xsl:copy-of select="@*"/>
+ <xsl:apply-templates mode="addNS"/>
+ </xsl:element>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:copy>
+ <xsl:if test="not(parent::*)">
+ <xsl:attribute name="version">5.0</xsl:attribute>
+ </xsl:if>
+ <xsl:copy-of select="@*"/>
+ <xsl:apply-templates mode="addNS"/>
+ </xsl:copy>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template match="comment()|processing-instruction()|text()" mode="addNS">
+ <xsl:copy/>
+</xsl:template>
+
+<!-- ====================================================================== -->
+
+<xsl:template name="emit-message">
+ <xsl:param name="message"/>
+ <xsl:message>
+ <xsl:value-of select="$message"/>
+ <xsl:text> (</xsl:text>
+ <xsl:value-of select="$rootid"/>
+ <xsl:text>)</xsl:text>
+ </xsl:message>
+</xsl:template>
+
+</xsl:stylesheet>
--- /dev/null
+package org.argeo.app.jcr.odk;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+
+import javax.jcr.ImportUUIDBehavior;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.app.api.EntityMimeType;
+import org.argeo.app.api.EntityType;
+import org.argeo.app.odk.OdkNames;
+import org.argeo.app.odk.OrxListName;
+import org.argeo.app.odk.OrxManifestName;
+import org.argeo.cms.util.DigestUtils;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.jcr.JcrxApi;
+
+/** Utilities around ODK. */
+public class OdkJcrUtils {
+ private final static CmsLog log = CmsLog.getLog(OdkJcrUtils.class);
+
+ public static Node loadOdkForm(Node formBase, String name, InputStream in, InputStream... additionalNodes)
+ throws RepositoryException, IOException {
+ if (!formBase.isNodeType(EntityType.formSet.get()))
+ throw new IllegalArgumentException(
+ "Parent path " + formBase + " must be of type " + EntityType.formSet.get());
+ Node form = JcrUtils.getOrAdd(formBase, name, OrxListName.xform.get(), NodeType.MIX_VERSIONABLE);
+
+ String previousCsum = JcrxApi.getChecksum(form, JcrxApi.MD5);
+ String previousFormId = Jcr.get(form, OrxListName.formID.get());
+ String previousFormVersion = Jcr.get(form, OrxListName.version.get());
+
+ Session s = formBase.getSession();
+ s.importXML(form.getPath(), in, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
+
+ for (InputStream additionalIn : additionalNodes) {
+ s.importXML(form.getPath(), additionalIn, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
+ }
+ s.save();
+
+ // manage instances
+ // NodeIterator instances =
+ // form.getNodes("h:html/h:head/xforms:model/xforms:instance");
+ NodeIterator instances = form.getNode("h:html/h:head/xforms:model").getNodes("xforms:instance");
+ Node primaryInstance = null;
+ while (instances.hasNext()) {
+ Node instance = instances.nextNode();
+ if (primaryInstance == null) {
+ primaryInstance = instance;
+ } else {// secondary instances
+ String instanceId = instance.getProperty("id").getString();
+ URI instanceUri = null;
+ if (instance.hasProperty("src"))
+ try {
+ instanceUri = new URI(instance.getProperty("src").getString());
+ } catch (URISyntaxException e) {
+ throw new IllegalArgumentException("Instance " + instanceId + " has a badly formatted URI", e);
+ }
+ if (instanceUri != null) {
+ if ("jr".equals(instanceUri.getScheme())) {
+ String uuid;
+ String mimeType;
+ String encoding = StandardCharsets.UTF_8.name();
+ String type = instanceUri.getHost();
+ String path = instanceUri.getPath();
+ if ("file".equals(type)) {
+ if (!path.endsWith(".xml"))
+ throw new IllegalArgumentException("File uri " + instanceUri + " must end with .xml");
+ // Work around bug in ODK Collect not supporting paths
+ // path = path.substring(0, path.length() - ".xml".length());
+ // Node target = file.getSession().getNode(path);
+ uuid = path.substring(1, path.length() - ".xml".length());
+ mimeType = EntityMimeType.XML.getMimeType();
+ } else if ("file-csv".equals(type)) {
+ if (!path.endsWith(".csv"))
+ throw new IllegalArgumentException("File uri " + instanceUri + " must end with .csv");
+ // Work around bug in ODK Collect not supporting paths
+ // path = path.substring(0, path.length() - ".csv".length());
+ // Node target = file.getSession().getNode(path);
+ uuid = path.substring(1, path.length() - ".csv".length());
+ mimeType = EntityMimeType.CSV.getMimeType();
+ } else {
+ throw new IllegalArgumentException("Unsupported instance type " + type);
+ }
+ Node manifest = JcrUtils.getOrAdd(form, OrxManifestName.manifest.name(),
+ OrxManifestName.manifest.get());
+ Node file = JcrUtils.getOrAdd(manifest, instanceId);
+ file.addMixin(NodeType.MIX_MIMETYPE);
+ file.setProperty(Property.JCR_MIMETYPE, mimeType);
+ file.setProperty(Property.JCR_ENCODING, encoding);
+ Node target = file.getSession().getNodeByIdentifier(uuid);
+
+// if (target.isNodeType(NodeType.NT_QUERY)) {
+// Query query = target.getSession().getWorkspace().getQueryManager().getQuery(target);
+// query.setLimit(10);
+// QueryResult queryResult = query.execute();
+// RowIterator rit = queryResult.getRows();
+// while (rit.hasNext()) {
+// Row row = rit.nextRow();
+// for (Value value : row.getValues()) {
+// System.out.print(value.getString());
+// System.out.print(',');
+// }
+// System.out.print('\n');
+// }
+//
+// }
+
+ if (target.isNodeType(NodeType.MIX_REFERENCEABLE)) {
+ file.setProperty(Property.JCR_ID, target);
+ if (file.hasProperty(Property.JCR_PATH))
+ file.getProperty(Property.JCR_PATH).remove();
+ } else {
+ file.setProperty(Property.JCR_PATH, target.getPath());
+ if (file.hasProperty(Property.JCR_ID))
+ file.getProperty(Property.JCR_ID).remove();
+ }
+ }
+ }
+ }
+ }
+
+ if (primaryInstance == null)
+ throw new IllegalArgumentException("No primary instance found in " + form);
+ if (!primaryInstance.hasNodes())
+ throw new IllegalArgumentException("No data found in primary instance of " + form);
+ NodeIterator primaryInstanceChildren = primaryInstance.getNodes();
+ Node data = primaryInstanceChildren.nextNode();
+ if (primaryInstanceChildren.hasNext())
+ throw new IllegalArgumentException("More than one data found in primary instance of " + form);
+ String formId = data.getProperty("id").getString();
+ if (previousFormId != null && !formId.equals(previousFormId))
+ log.warn("Form id of " + form + " changed from " + previousFormId + " to " + formId);
+ form.setProperty(OrxListName.formID.get(), formId);
+ String formVersion = data.getProperty("version").getString();
+
+ if (previousCsum == null)// save before checksuming
+ s.save();
+ String newCsum;
+ try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+ s.exportDocumentView(form.getPath() + "/" + OdkNames.H_HTML, out, true, false);
+ newCsum = DigestUtils.digest(DigestUtils.MD5, out.toByteArray());
+ }
+ if (previousCsum == null) {
+ JcrxApi.addChecksum(form, newCsum);
+ JcrUtils.updateLastModified(form);
+ form.setProperty(OrxListName.version.get(), formVersion);
+ s.save();
+ s.getWorkspace().getVersionManager().checkpoint(form.getPath());
+ if (log.isDebugEnabled())
+ log.debug("New form " + form);
+ } else {
+ if (newCsum.equals(previousCsum)) {
+ // discard
+ s.refresh(false);
+ if (log.isDebugEnabled())
+ log.debug("Unmodified form " + form);
+ return form;
+ } else {
+ if (formVersion.equals(previousFormVersion)) {
+ s.refresh(false);
+ throw new IllegalArgumentException("Form " + form + " has been changed but version " + formVersion
+ + " has not been changed, discarding changes...");
+ }
+ form.setProperty(OrxListName.version.get(), formVersion);
+ JcrxApi.addChecksum(form, newCsum);
+ JcrUtils.updateLastModified(form);
+ s.save();
+ s.getWorkspace().getVersionManager().checkpoint(form.getPath());
+ if (log.isDebugEnabled()) {
+ log.debug("Updated form " + form);
+ log.debug("Previous csum " + previousCsum);
+ log.debug("New csum " + newCsum);
+ }
+ }
+ }
+ return form;
+ }
+
+ /** Singleton. */
+ private OdkJcrUtils() {
+
+ }
+
+}
--- /dev/null
+package org.argeo.app.jcr.terms;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.argeo.app.api.Term;
+
+/**
+ * A single term. Helper to optimise {@link SuiteTermsManager} implementation.
+ */
+class SuiteTerm implements Term {
+ private final String name;
+ private final String relativePath;
+ private final SuiteTypology typology;
+ private final String id;
+
+ private final SuiteTerm parentTerm;
+ private final List<SuiteTerm> subTerms = new ArrayList<>();
+
+ SuiteTerm(SuiteTypology typology, String relativePath, SuiteTerm parentTerm) {
+ this.typology = typology;
+ this.parentTerm = parentTerm;
+ this.relativePath = relativePath;
+ int index = relativePath.lastIndexOf('/');
+ if (index > 0) {
+ this.name = relativePath.substring(index + 1);
+ } else {
+ this.name = relativePath;
+ }
+ id = typology.getName() + '/' + relativePath;
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ public String getRelativePath() {
+ return relativePath;
+ }
+
+ @Override
+ public SuiteTypology getTypology() {
+ return typology;
+ }
+
+ @Override
+ public List<SuiteTerm> getSubTerms() {
+ return subTerms;
+ }
+
+ @Override
+ public SuiteTerm getParentTerm() {
+ return parentTerm;
+ }
+
+}
--- /dev/null
+package org.argeo.app.jcr.terms;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.app.api.EntityNames;
+import org.argeo.app.api.EntityType;
+import org.argeo.app.api.Term;
+import org.argeo.app.api.TermsManager;
+import org.argeo.cms.jcr.CmsJcrUtils;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrException;
+
+/** Argeo Suite implementation of terms manager. */
+public class SuiteTermsManager implements TermsManager {
+ private final Map<String, SuiteTerm> terms = new HashMap<>();
+ private final Map<String, SuiteTypology> typologies = new HashMap<>();
+
+ // JCR
+ private Repository repository;
+ private Session adminSession;
+
+ public void init() {
+ adminSession = CmsJcrUtils.openDataAdminSession(repository, CmsConstants.SYS_WORKSPACE);
+ }
+
+ @Override
+ public List<Term> listAllTerms(String typology) {
+ List<Term> res = new ArrayList<>();
+ SuiteTypology t = getTypology(typology);
+ for (SuiteTerm term : t.getAllTerms()) {
+ res.add(term);
+ }
+ return res;
+ }
+
+ @Override
+ public SuiteTerm getTerm(String termId) {
+ return terms.get(termId);
+ }
+
+ @Override
+ public SuiteTypology getTypology(String typology) {
+ SuiteTypology t = typologies.get(typology);
+ if (t == null) {
+ Node termsNode = Jcr.getNode(adminSession, "SELECT * FROM [{0}] WHERE NAME()=\"{1}\"",
+ EntityType.terms.get(), typology);
+ if (termsNode == null)
+ throw new IllegalArgumentException("Typology " + typology + " not found.");
+ t = loadTypology(termsNode);
+ }
+ return t;
+ }
+
+ SuiteTypology loadTypology(Node termsNode) {
+ try {
+ SuiteTypology typology = new SuiteTypology(termsNode);
+ for (Node termNode : Jcr.iterate(termsNode.getNodes())) {
+ if (termNode.isNodeType(EntityType.term.get())) {
+ SuiteTerm term = loadTerm(typology, termNode, null);
+ if (!term.getSubTerms().isEmpty())
+ typology.markNotFlat();
+ typology.getSubTerms().add(term);
+ }
+ }
+ typologies.put(typology.getName(), typology);
+ return typology;
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot load typology from " + termsNode, e);
+ }
+ }
+
+ SuiteTerm loadTerm(SuiteTypology typology, Node termNode, SuiteTerm parentTerm) throws RepositoryException {
+ String name = termNode.getProperty(EntityNames.NAME).getString();
+ String relativePath = parentTerm == null ? name : parentTerm.getRelativePath() + '/' + name;
+ SuiteTerm term = new SuiteTerm(typology, relativePath, parentTerm);
+ terms.put(term.getId(), term);
+ for (Node subTermNode : Jcr.iterate(termNode.getNodes())) {
+ if (termNode.isNodeType(EntityType.term.get())) {
+ SuiteTerm subTerm = loadTerm(typology, subTermNode, term);
+ term.getSubTerms().add(subTerm);
+ }
+ }
+ return term;
+ }
+
+ public void destroy() {
+ Jcr.logout(adminSession);
+ }
+
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+}
--- /dev/null
+package org.argeo.app.jcr.terms;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+
+import org.argeo.app.api.Term;
+import org.argeo.app.api.Typology;
+import org.argeo.jcr.Jcr;
+
+/** A typology. Helper to optimise {@link SuiteTermsManager} implementation. */
+class SuiteTypology implements Typology {
+ private final String name;
+ private final Node node;
+ private boolean isFlat = true;
+
+ private final List<SuiteTerm> subTerms = new ArrayList<>();
+
+ public SuiteTypology(Node node) {
+ this.node = node;
+ this.name = Jcr.getName(this.node);
+ }
+
+ @Override
+ public String getId() {
+ return name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Node getNode() {
+ return node;
+ }
+
+ void markNotFlat() {
+ if (isFlat)
+ isFlat = false;
+ }
+
+ @Override
+ public boolean isFlat() {
+ return isFlat;
+ }
+
+ @Override
+ public List<SuiteTerm> getSubTerms() {
+ return subTerms;
+ }
+
+ public List<SuiteTerm> getAllTerms() {
+ if (isFlat)
+ return subTerms;
+ else {
+ List<SuiteTerm> terms = new ArrayList<>();
+ for (SuiteTerm subTerm : subTerms) {
+ terms.add(subTerm);
+ collectSubTerms(terms, subTerm);
+ }
+ return terms;
+ }
+ }
+
+ public Term findTermByName(String name) {
+ List<SuiteTerm> collected = new ArrayList<>();
+ for (SuiteTerm subTerm : subTerms) {
+ collectTermsByName(subTerm, name, collected);
+ }
+ if (collected.isEmpty())
+ return null;
+ if (collected.size() == 1)
+ return collected.get(0);
+ throw new IllegalArgumentException(
+ "There are " + collected.size() + " terms with name " + name + " in typology " + getId());
+ }
+
+ private void collectTermsByName(SuiteTerm term, String name, List<SuiteTerm> collected) {
+ if (term.getName().equals(name)) {
+ collected.add(term);
+ }
+ for (SuiteTerm subTerm : term.getSubTerms()) {
+ collectTermsByName(subTerm, name, collected);
+ }
+ }
+
+ private void collectSubTerms(List<SuiteTerm> terms, SuiteTerm term) {
+ for (SuiteTerm subTerm : term.getSubTerms()) {
+ terms.add(subTerm);
+ collectSubTerms(terms, subTerm);
+ }
+ }
+
+}
--- /dev/null
+package org.argeo.internal.app.jcr;
+
+import javax.jcr.Node;
+
+import org.argeo.api.acr.Content;
+import org.argeo.api.acr.ContentSession;
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.api.cms.CmsSession;
+import org.argeo.app.api.AppUserState;
+import org.argeo.app.jcr.SuiteJcrUtils;
+import org.argeo.cms.acr.ContentUtils;
+import org.argeo.cms.jcr.acr.JcrContentProvider;
+import org.argeo.jcr.Jcr;
+
+public class AppUserStateImpl implements AppUserState {
+ private JcrContentProvider jcrContentProvider;
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public Content getOrCreateSessionDir(ContentSession contentSession, CmsSession session) {
+ Node userDirNode = jcrContentProvider.doInAdminSession((adminSession) -> {
+ Node node = SuiteJcrUtils.getOrCreateCmsSessionNode(adminSession, session);
+ return node;
+ });
+ Content userDir = contentSession
+ .get(ContentUtils.SLASH + CmsConstants.SYS_WORKSPACE + Jcr.getPath(userDirNode));
+ return userDir;
+ }
+
+ public void setJcrContentProvider(JcrContentProvider jcrContentProvider) {
+ this.jcrContentProvider = jcrContentProvider;
+ }
+
+}
--- /dev/null
+package org.argeo.internal.app.jcr;
+
+import java.io.IOException;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.security.Privilege;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.app.api.EntityType;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.maintenance.AbstractMaintenanceService;
+
+/** Initialises JCR in an Argeo Suite backend. */
+public class SuiteMaintenanceService extends AbstractMaintenanceService {
+ @Override
+ public boolean prepareJcrTree(Session adminSession) throws RepositoryException, IOException {
+ boolean modified = false;
+ Node rootNode = adminSession.getRootNode();
+ if (!rootNode.hasNode(EntityType.user.name())) {
+ rootNode.addNode(EntityType.user.name(), NodeType.NT_UNSTRUCTURED);
+ modified = true;
+ }
+ if (modified)
+ adminSession.save();
+ return modified;
+ }
+
+ @Override
+ public void configurePrivileges(Session adminSession) throws RepositoryException {
+ JcrUtils.addPrivilege(adminSession, EntityType.user.basePath(), CmsConstants.ROLE_USER_ADMIN,
+ Privilege.JCR_ALL);
+ // JcrUtils.addPrivilege(adminSession, "/", SuiteRole.coworker.dn(),
+ // Privilege.JCR_READ);
+ }
+
+}
import org.argeo.api.cms.CmsLog;
import org.argeo.api.cms.CmsSession;
-import org.argeo.app.core.SuiteUtils;
import org.argeo.app.image.ImageProcessor;
+import org.argeo.app.jcr.SuiteJcrUtils;
import org.argeo.app.odk.OrxType;
import org.argeo.app.xforms.FormSubmissionListener;
import org.argeo.cms.auth.RemoteAuthRequest;
import org.argeo.cms.auth.RemoteAuthUtils;
import org.argeo.cms.jcr.CmsJcrUtils;
+import org.argeo.cms.jcr.acr.JcrContent;
import org.argeo.cms.servlet.ServletHttpRequest;
import org.argeo.jcr.Jcr;
import org.argeo.jcr.JcrUtils;
resp.setContentType("text/xml; charset=utf-8");
resp.setHeader("X-OpenRosa-Version", "1.0");
resp.setDateHeader("Date", System.currentTimeMillis());
-
+
// should be set in HEAD? Let's rather use defaults.
- //resp.setIntHeader("X-OpenRosa-Accept-Content-Length", 1024 * 1024);
+ // resp.setIntHeader("X-OpenRosa-Accept-Content-Length", 1024 * 1024);
RemoteAuthRequest request = new ServletHttpRequest(req);
Session session = RemoteAuthUtils.doAs(() -> Jcr.login(repository, null), request);
try {
// TODO centralise at a deeper level
adminSession = CmsJcrUtils.openDataAdminSession(repository, null);
- SuiteUtils.getOrCreateCmsSessionNode(adminSession, cmsSession);
+ SuiteJcrUtils.getOrCreateCmsSessionNode(adminSession, cmsSession);
} finally {
Jcr.logout(adminSession);
}
try {
- Node cmsSessionNode = SuiteUtils.getCmsSessionNode(session, cmsSession);
+ Node cmsSessionNode = SuiteJcrUtils.getCmsSessionNode(session, cmsSession);
Node submission = cmsSessionNode.addNode(submissionNameFormatter.format(Instant.now()),
OrxType.submission.get());
for (Part part : req.getParts()) {
session.save();
try {
for (FormSubmissionListener submissionListener : submissionListeners) {
- submissionListener.formSubmissionReceived(submission);
+ submissionListener.formSubmissionReceived(JcrContent.nodeToContent(submission));
}
} catch (Exception e) {
log.error("Cannot save submision, cancelling...", e);
import org.argeo.api.cms.CmsLog;
import org.argeo.api.cms.ux.CmsTheme;
import org.argeo.app.docbook.DbkType;
-import org.argeo.app.docbook.DbkUtils;
+import org.argeo.app.jcr.docbook.DbkJcrUtils;
import org.argeo.cms.auth.RemoteAuthUtils;
import org.argeo.cms.servlet.ServletHttpRequest;
import org.argeo.jcr.Jcr;
if (node.hasNode(DbkType.article.get())) {
Node dbkNode = node.getNode(DbkType.article.get());
- if (DbkUtils.isDbk(dbkNode)) {
+ if (DbkJcrUtils.isDbk(dbkNode)) {
CmsTheme cmsTheme = null;
String themeId = req.getParameter("themeId");
if (themeId != null) {
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.product.knowledge</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ds.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+appTitle=Argeo Knowledge
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.argeo.product.knowledge.swtArgeoApp">
+ <implementation class="org.argeo.app.swt.ux.SwtArgeoApp"/>
+ <service>
+ <provide interface="org.argeo.api.cms.CmsApp"/>
+ </service>
+ <properties entry="config/swtArgeoApp.properties"/>
+ <reference bind="addUiProvider" cardinality="0..n" interface="org.argeo.cms.swt.acr.SwtUiProvider" policy="dynamic" unbind="removeUiProvider"/>
+ <reference bind="addTheme" cardinality="1..n" interface="org.argeo.api.cms.ux.CmsTheme" name="CmsTheme" policy="dynamic" unbind="removeTheme"/>
+ <reference bind="addLayer" cardinality="1..n" interface="org.argeo.app.swt.ux.SwtAppLayer" name="SuiteLayer" policy="dynamic" unbind="removeLayer"/>
+ <reference bind="setCmsContext" cardinality="1..1" interface="org.argeo.api.cms.CmsContext" name="CmsContext" policy="static"/>
+ <reference bind="setContentRepository" cardinality="1..1" interface="org.argeo.api.acr.ContentRepository" name="ContentRepository" policy="static"/>
+ <reference bind="setAppUserState" cardinality="1..1" interface="org.argeo.app.api.AppUserState" name="AppUserState" policy="static"/>
+</scr:component>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Terms Entry Area">
+ <implementation class="org.argeo.app.swt.terms.TermsEntryArea"/>
+ <service>
+ <provide interface="org.argeo.cms.swt.acr.SwtUiProvider"/>
+ </service>
+ <property name="service.ranking" type="Integer" value="-1000"/>
+ <properties entry="config/termsEntryArea.properties"/>
+</scr:component>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Terms Layer">
+ <implementation class="org.argeo.app.swt.ux.DefaultEditionLayer"/>
+ <service>
+ <provide interface="org.argeo.app.swt.ux.SwtAppLayer"/>
+ </service>
+ <property name="service.ranking" type="Integer" value="-1000"/>
+ <properties entry="config/termsLayer.properties"/>
+ <reference bind="setEntryArea" cardinality="1..1" interface="org.argeo.cms.swt.acr.SwtUiProvider" name="CmsUiProvider" policy="dynamic" target="(service.pid=argeo.suite.ui.termsEntryArea)"/>
+</scr:component>
--- /dev/null
+Service-Component:\
+OSGI-INF/swtArgeoApp.xml,\
+OSGI-INF/termsEntryArea.xml,\
+OSGI-INF/termsLayer.xml,\
+
+Import-Package:\
+org.argeo.app.swt.ux,\
+org.argeo.app.swt.terms,\
+*
\ No newline at end of file
--- /dev/null
+bin.includes = META-INF/,\
+ .,\
+ OSGI-INF/swtArgeoApp.xml
+source.. = src/
+output.. = bin/
--- /dev/null
+service.pid=argeo.product.knowledge.swtArgeoApp
+
+event.topics=argeo/suite/*
+
+argeo.cms.app.contextName=argeo/knowledge
\ No newline at end of file
--- /dev/null
+service.pid=argeo.suite.ui.termsEntryArea
--- /dev/null
+service.pid=argeo.suite.ui.termsLayer
+title=Terms
+icon=dashboard
+
+entity.type=entity:terms,entity:term
\ No newline at end of file
argeo.osgi.start.5=\
org.argeo.app.profile.acr.fs,\
org.argeo.app.core,\
+org.argeo.app.jcr,\
org.argeo.app.ui,\
org.argeo.app.theme.default,\
org.argeo.app.servlet.publish,\
-org.argeo.app.servlet.odk
+org.argeo.app.servlet.odk,\
+org.argeo.product.knowledge,\
# Local
--- /dev/null
+package org.argeo.app.swt.terms;
+
+import org.argeo.api.acr.Content;
+import org.argeo.cms.swt.acr.SwtUiProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+
+/** Entry area for managing the typologies. */
+public class TermsEntryArea implements SwtUiProvider {
+
+ @Override
+ public Control createUiPart(Composite parent, Content content) {
+ parent.setLayout(new GridLayout());
+ Label lbl = new Label(parent, SWT.NONE);
+ lbl.setText("Typologies");
+ return lbl;
+ }
+
+}
+appTitle=Argeo Suite
+
people=People
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Terms Entry Area">
- <implementation class="org.argeo.app.ui.TermsEntryArea"/>
- <service>
- <provide interface="org.argeo.cms.swt.acr.SwtUiProvider"/>
- </service>
- <property name="service.ranking" type="Integer" value="-1000"/>
- <properties entry="config/termsEntryArea.properties"/>
-</scr:component>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Terms Layer">
- <implementation class="org.argeo.app.swt.ux.DefaultEditionLayer"/>
- <service>
- <provide interface="org.argeo.app.swt.ux.SwtAppLayer"/>
- </service>
- <property name="service.ranking" type="Integer" value="-1000"/>
- <properties entry="config/termsLayer.properties"/>
- <reference bind="setEntryArea" cardinality="1..1" interface="org.argeo.cms.swt.acr.SwtUiProvider" name="CmsUiProvider" policy="dynamic" target="(service.pid=argeo.suite.ui.termsEntryArea)"/>
-</scr:component>
OSGI-INF/loginScreen.xml,\
OSGI-INF/recentItems.xml,\
OSGI-INF/adminLeadPane.xml,\
-OSGI-INF/termsEntryArea.xml,\
-OSGI-INF/termsLayer.xml,\
OSGI-INF/dashboard.xml,\
OSGI-INF/dashboardLayer.xml,\
OSGI-INF/peopleEntryArea.xml,\
+++ /dev/null
-service.pid=argeo.suite.ui.termsEntryArea
+++ /dev/null
-service.pid=argeo.suite.ui.termsLayer
-title=Terms
-icon=dashboard
-
-entity.type=entity:terms,entity:term
\ No newline at end of file
import javax.jcr.query.QueryResult;
import org.argeo.app.api.EntityType;
-import org.argeo.app.core.XPathUtils;
+import org.argeo.app.jcr.XPathUtils;
import org.argeo.app.ui.widgets.DelayedText;
import org.argeo.app.ux.SuiteIcon;
import org.argeo.app.ux.SuiteUxEvent;
+++ /dev/null
-package org.argeo.app.ui;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.ui.CmsUiProvider;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-
-/** Entry area for managing th etypologies. */
-public class TermsEntryArea implements CmsUiProvider {
-
- @Override
- public Control createUi(Composite parent, Node context) throws RepositoryException {
- parent.setLayout(new GridLayout());
- Label lbl = new Label(parent, SWT.NONE);
- lbl.setText("Typologies");
- return lbl;
- }
-
-}
package org.argeo.app.ui.docbook;
import static org.argeo.app.docbook.DbkType.para;
-import static org.argeo.app.docbook.DbkUtils.addDbk;
-import static org.argeo.app.docbook.DbkUtils.isDbk;
+import static org.argeo.app.jcr.docbook.DbkJcrUtils.addDbk;
+import static org.argeo.app.jcr.docbook.DbkJcrUtils.isDbk;
import java.util.ArrayList;
import java.util.Iterator;
import org.argeo.api.cms.ux.CmsEditable;
import org.argeo.app.docbook.DbkAttr;
import org.argeo.app.docbook.DbkType;
-import org.argeo.app.docbook.DbkUtils;
+import org.argeo.app.jcr.docbook.DbkJcrUtils;
import org.argeo.cms.swt.CmsSwtUtils;
import org.argeo.cms.swt.SwtEditablePart;
import org.argeo.cms.ui.viewers.AbstractPageViewer;
protected DbkSectionTitle prepareSectionTitle(Section newSection, String titleText) throws RepositoryException {
Node sectionNode = newSection.getNode();
- Node titleNode = DbkUtils.getOrAddDbk(sectionNode, DbkType.title);
+ Node titleNode = DbkJcrUtils.getOrAddDbk(sectionNode, DbkType.title);
getTextInterpreter().write(titleNode, titleText);
if (newSection.getHeader() == null)
newSection.createHeader();
((Control) sp).dispose();
}
// create title
- Node titleNode = DbkUtils.addDbk(newSectionNode, DbkType.title);
+ Node titleNode = DbkJcrUtils.addDbk(newSectionNode, DbkType.title);
// newSectionNode.addNode(DocBookType.TITLE, DocBookType.TITLE);
getTextInterpreter().write(titleNode, txt);
import org.argeo.api.cms.ux.CmsEditable;
import org.argeo.app.docbook.DbkMsg;
-import org.argeo.app.docbook.DbkUtils;
+import org.argeo.app.jcr.docbook.DbkJcrUtils;
import org.argeo.cms.swt.CmsSwtUtils;
import org.argeo.cms.swt.SwtEditablePart;
import org.argeo.cms.swt.MouseDown;
Label insertPictureB = new Label(parent, SWT.NONE);
insertPictureB.setText(DbkMsg.insertPicture.lead());
insertPictureB.addMouseListener((MouseDown) (e) -> {
- Node newNode = DbkUtils.insertImageAfter(nodePart.getNode());
+ Node newNode = DbkJcrUtils.insertImageAfter(nodePart.getNode());
Jcr.save(newNode);
textViewer.insertPart(section, newNode);
hide();
Label insertVideoB = new Label(parent, SWT.NONE);
insertVideoB.setText(DbkMsg.insertVideo.lead());
insertVideoB.addMouseListener((MouseDown) (e) -> {
- Node newNode = DbkUtils.insertVideoAfter(nodePart.getNode());
+ Node newNode = DbkJcrUtils.insertVideoAfter(nodePart.getNode());
Jcr.save(newNode);
textViewer.insertPart(section, newNode);
hide();
import org.argeo.app.api.EntityType;
import org.argeo.app.docbook.DbkAttr;
import org.argeo.app.docbook.DbkType;
-import org.argeo.app.docbook.DbkUtils;
+import org.argeo.app.jcr.docbook.DbkJcrUtils;
import org.argeo.cms.ui.util.CmsUiUtils;
import org.argeo.cms.ui.util.DefaultImageManager;
import org.argeo.jcr.JcrException;
@Override
public Binary getImageBinary(Node node) {
Node fileNode = null;
- if (DbkUtils.isDbk(node, DbkType.mediaobject)) {
+ if (DbkJcrUtils.isDbk(node, DbkType.mediaobject)) {
Node imageDataNode = getImageDataNode(node);
fileNode = getFileNode(imageDataNode);
}
import static org.argeo.app.docbook.DbkType.para;
import static org.argeo.app.docbook.DbkType.title;
-import static org.argeo.app.docbook.DbkUtils.isDbk;
+import static org.argeo.app.jcr.docbook.DbkJcrUtils.isDbk;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import org.argeo.api.acr.ldap.NamingUtils;
import org.argeo.app.docbook.DbkAttr;
import org.argeo.app.docbook.DbkType;
-import org.argeo.app.docbook.DbkUtils;
+import org.argeo.app.jcr.docbook.DbkJcrUtils;
import org.argeo.cms.swt.CmsSwtUtils;
import org.argeo.cms.swt.Selected;
import org.argeo.cms.ui.viewers.NodePart;
Composite editor = new Composite(wrapper, SWT.BORDER);
editor.setLayout(new GridLayout(3, false));
editor.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
- String fileref = DbkUtils.getMediaFileref(mediaobject);
+ String fileref = DbkJcrUtils.getMediaFileref(mediaobject);
Text text = new Text(editor, SWT.SINGLE);
if (fileref != null)
text.setText(fileref);
if (control instanceof Browser) {
Browser browser = (Browser) control;
getNode().getSession();
- String fileref = DbkUtils.getMediaFileref(getNode());
+ String fileref = DbkJcrUtils.getMediaFileref(getNode());
if (fileref != null) {
// TODO manage self-hosted videos
// TODO for YouTube videos, check whether the URL starts with
import org.argeo.api.cms.ux.CmsEditable;
import org.argeo.app.docbook.DbkType;
-import org.argeo.app.docbook.DbkUtils;
+import org.argeo.app.jcr.docbook.DbkJcrUtils;
import org.argeo.cms.swt.CmsSwtUtils;
import org.eclipse.swt.widgets.Composite;
@Override
protected void initModel(Node textNode) throws RepositoryException {
if (isFlat()) {
- DbkUtils.addParagraph(textNode, "");
+ DbkJcrUtils.addParagraph(textNode, "");
}
// else
// textNode.setProperty(DocBookNames.DBK_TITLE, textNode.getName());