From: Mathieu Baudier Date: Wed, 4 Nov 2020 08:00:22 +0000 (+0100) Subject: Merge remote-tracking branch 'origin/sleroy' X-Git-Tag: argeo-suite-2.1.16~42 X-Git-Url: http://git.argeo.org/?p=gpl%2Fargeo-suite.git;a=commitdiff_plain;h=1901817b83c8e1fc3f94d3c8a801a59f52b78a84;hp=fed56d58f4c9e48b6d8b0edee36928294ae31264 Merge remote-tracking branch 'origin/sleroy' --- diff --git a/dep/org.argeo.suite.dep.ui.rap/pom.xml b/dep/org.argeo.suite.dep.ui.rap/pom.xml index fa251f4..8cba39e 100644 --- a/dep/org.argeo.suite.dep.ui.rap/pom.xml +++ b/dep/org.argeo.suite.dep.ui.rap/pom.xml @@ -60,11 +60,21 @@ + + org.argeo.suite + org.argeo.support.xforms + 2.1.16-SNAPSHOT + org.argeo.suite org.argeo.support.odk 2.1.16-SNAPSHOT + + org.argeo.suite + org.argeo.support.geonames + 2.1.16-SNAPSHOT + diff --git a/knowledge/org.argeo.support.geonames/.classpath b/knowledge/org.argeo.support.geonames/.classpath new file mode 100644 index 0000000..e801ebf --- /dev/null +++ b/knowledge/org.argeo.support.geonames/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/knowledge/org.argeo.support.geonames/.gitignore b/knowledge/org.argeo.support.geonames/.gitignore new file mode 100644 index 0000000..09e3bc9 --- /dev/null +++ b/knowledge/org.argeo.support.geonames/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/target/ diff --git a/knowledge/org.argeo.support.geonames/.project b/knowledge/org.argeo.support.geonames/.project new file mode 100644 index 0000000..3c8181f --- /dev/null +++ b/knowledge/org.argeo.support.geonames/.project @@ -0,0 +1,28 @@ + + + org.argeo.support.geonames + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/knowledge/org.argeo.support.geonames/META-INF/.gitignore b/knowledge/org.argeo.support.geonames/META-INF/.gitignore new file mode 100644 index 0000000..4854a41 --- /dev/null +++ b/knowledge/org.argeo.support.geonames/META-INF/.gitignore @@ -0,0 +1 @@ +/MANIFEST.MF diff --git a/knowledge/org.argeo.support.geonames/bnd.bnd b/knowledge/org.argeo.support.geonames/bnd.bnd new file mode 100644 index 0000000..e69de29 diff --git a/knowledge/org.argeo.support.geonames/build.properties b/knowledge/org.argeo.support.geonames/build.properties new file mode 100644 index 0000000..34d2e4d --- /dev/null +++ b/knowledge/org.argeo.support.geonames/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/knowledge/org.argeo.support.geonames/pom.xml b/knowledge/org.argeo.support.geonames/pom.xml new file mode 100644 index 0000000..83244c2 --- /dev/null +++ b/knowledge/org.argeo.support.geonames/pom.xml @@ -0,0 +1,22 @@ + + + 4.0.0 + + org.argeo.suite + knowledge + 2.1.16-SNAPSHOT + .. + + org.argeo.support.geonames + Geonames support + jar + + + org.argeo.commons + org.argeo.cms + ${version.argeo-commons} + + + diff --git a/knowledge/org.argeo.support.geonames/src/org/argeo/support/geonames/GeonamesAdm.java b/knowledge/org.argeo.support.geonames/src/org/argeo/support/geonames/GeonamesAdm.java new file mode 100644 index 0000000..d578272 --- /dev/null +++ b/knowledge/org.argeo.support.geonames/src/org/argeo/support/geonames/GeonamesAdm.java @@ -0,0 +1,157 @@ +package org.argeo.support.geonames; + +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +/** A Geonames administrative subdivision. */ +public class GeonamesAdm { + private final Long geonameId; + private final String countryCode; + private final String adminCode1; + private final String admLevel; + private final Integer level; + private final String name; + private final String asciiName; + private final List alternateNames; + private final Double lat; + private final Double lng; + private final LocalDate lastUpdated; + private final ZoneId timeZone; + + private final Long[] upperLevelIds = new Long[5]; + private final List upperLevels = new ArrayList<>(); + + private List row; + + /** Initialise from a row in the main Geonames table. */ + public GeonamesAdm(List row) { + geonameId = Long.parseLong(row.get(0)); + admLevel = row.get(7); + countryCode = row.get(8); + adminCode1 = row.get(10); + if (admLevel.startsWith("ADM")) { + if (admLevel.endsWith("H")) + level = Integer.parseInt(admLevel.substring(3, admLevel.length() - 1)); + else + level = Integer.parseInt(admLevel.substring(3)); + } else if (admLevel.equals("PCLI")) { + level = 0; + } else { + throw new IllegalArgumentException("Unsupported admin level " + admLevel); + } + name = row.get(1); + asciiName = row.get(2); + alternateNames = Arrays.asList(row.get(3).split(",")); + lat = Double.parseDouble(row.get(4)); + lng = Double.parseDouble(row.get(5)); + lastUpdated = LocalDate.parse(row.get(18)); + timeZone = ZoneId.of(row.get(17)); + // upper levels + if (row.get(11) != null && !row.get(11).trim().equals("")) + upperLevelIds[2] = Long.parseLong(row.get(11)); + if (row.get(12) != null && !row.get(12).trim().equals("")) + upperLevelIds[3] = Long.parseLong(row.get(12)); + if (row.get(13) != null && !row.get(13).trim().equals("")) + upperLevelIds[4] = Long.parseLong(row.get(13)); + this.row = row; + } + + public void mapUpperLevels(Map index) { + for (int i = 0; i < level; i++) { + Long geonameId = upperLevelIds[i]; + upperLevels.add(i, index.get(geonameId)); + } + } + + public Long getGeonameId() { + return geonameId; + } + + public Integer getLevel() { + return level; + } + + public String getName() { + return name; + } + + public String getName(Function transform) { + if (transform != null) + return transform.apply(name); + else + return name; + + } + + public String getAsciiName() { + return asciiName; + } + + public List getAlternateNames() { + return alternateNames; + } + + public Double getLat() { + return lat; + } + + public Double getLng() { + return lng; + } + + public String getCountryCode() { + return countryCode; + } + + public String getAdmLevel() { + return admLevel; + } + + public List getRow() { + return row; + } + + public LocalDate getLastUpdated() { + return lastUpdated; + } + + public ZoneId getTimeZone() { + return timeZone; + } + + public String getAdminCode1() { + return adminCode1; + } + + public Long[] getUpperLevelIds() { + return upperLevelIds; + } + + public List getUpperLevels() { + return upperLevels; + } + + @Override + public int hashCode() { + return geonameId.intValue(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof GeonamesAdm)) + return false; + GeonamesAdm other = (GeonamesAdm) obj; + return geonameId.equals(other.geonameId); + } + + @Override + public String toString() { + return name + " (ADM" + level + " " + geonameId + ")"; + } + +} diff --git a/knowledge/org.argeo.support.geonames/src/org/argeo/support/geonames/ImportGeonamesAdmin.java b/knowledge/org.argeo.support.geonames/src/org/argeo/support/geonames/ImportGeonamesAdmin.java new file mode 100644 index 0000000..9af5987 --- /dev/null +++ b/knowledge/org.argeo.support.geonames/src/org/argeo/support/geonames/ImportGeonamesAdmin.java @@ -0,0 +1,93 @@ +package org.argeo.support.geonames; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.argeo.util.CsvParser; +import org.argeo.util.CsvWriter; + +/** Import GeoNames administrative division from the main table. */ +public class ImportGeonamesAdmin { + // private Log log = LogFactory.getLog(ImportGeonamesAdmin.class); + private Map geonamesAdms = new HashMap<>(); + + /** Loads the data. */ + public void parse(InputStream in) { + Map countryGeonameIds = new HashMap<>(); + Map admin1GeonameIds = new HashMap<>(); + CsvParser csvParser = new CsvParser() { + + @Override + protected void processLine(Integer lineNumber, List header, List tokens) { + if (!"A".equals(tokens.get(6))) + return; + GeonamesAdm geonamesAdm = new GeonamesAdm(tokens); + geonamesAdms.put(geonamesAdm.getGeonameId(), geonamesAdm); + if (geonamesAdm.getAdmLevel().equals("PCLI")) + countryGeonameIds.put(geonamesAdm.getCountryCode(), geonamesAdm.getGeonameId()); + if (geonamesAdm.getAdmLevel().equals("ADM1")) + admin1GeonameIds.put(geonamesAdm.getAdminCode1(), geonamesAdm.getGeonameId()); + } + }; + csvParser.setSeparator('\t'); + csvParser.setNoHeader(true); + csvParser.parse(in, StandardCharsets.UTF_8); + + // fill upper levels + for (GeonamesAdm adm : geonamesAdms.values()) { + adm.getUpperLevelIds()[0] = countryGeonameIds.get(adm.getCountryCode()); + if (adm.getLevel() > 0) + adm.getUpperLevelIds()[1] = admin1GeonameIds.get(adm.getAdminCode1()); + adm.mapUpperLevels(geonamesAdms); + } + + } + + public Map getGeonamesAdms() { + return geonamesAdms; + } + + /** + * Copies only the Geonames of feature class 'A' (administrative subdivisions). + */ + public static void filterGeonamesAdm(InputStream in, OutputStream out) { + CsvWriter csvWriter = new CsvWriter(out, StandardCharsets.UTF_8); + csvWriter.setSeparator('\t'); + CsvParser csvParser = new CsvParser() { + + @Override + protected void processLine(Integer lineNumber, List header, List tokens) { + if (tokens.size() < 7 || !"A".equals(tokens.get(6))) + return; + csvWriter.writeLine(tokens); + } + }; + csvParser.setSeparator('\t'); + csvParser.setNoHeader(true); + csvParser.parse(in, StandardCharsets.UTF_8); + } + + public static void main(String[] args) throws IOException { +// String country = "allCountries"; + String country = "CI"; +// try (InputStream in = Files +// .newInputStream(Paths.get(System.getProperty("user.home") + "/gis/data/geonames/" + country + ".txt")); +// OutputStream out = Files.newOutputStream( +// Paths.get(System.getProperty("user.home") + "/gis/data/geonames/" + country + "-adm.txt"))) { +// ImportGeonamesAdmin.filterGeonamesAdm(in, out); +// } + try (InputStream in = Files.newInputStream( + Paths.get(System.getProperty("user.home") + "/gis/data/geonames/" + country + "-adm.txt"))) { + ImportGeonamesAdmin importGeonamesAdmin = new ImportGeonamesAdmin(); + importGeonamesAdmin.parse(in); + } + } + +} diff --git a/knowledge/org.argeo.support.odk/OSGI-INF/odkFormListServlet.xml b/knowledge/org.argeo.support.odk/OSGI-INF/odkFormListServlet.xml index 852423b..e290933 100644 --- a/knowledge/org.argeo.support.odk/OSGI-INF/odkFormListServlet.xml +++ b/knowledge/org.argeo.support.odk/OSGI-INF/odkFormListServlet.xml @@ -7,4 +7,5 @@ + diff --git a/knowledge/org.argeo.support.odk/OSGI-INF/odkFormServlet.xml b/knowledge/org.argeo.support.odk/OSGI-INF/odkFormServlet.xml index 59d2de2..7f7e4db 100644 --- a/knowledge/org.argeo.support.odk/OSGI-INF/odkFormServlet.xml +++ b/knowledge/org.argeo.support.odk/OSGI-INF/odkFormServlet.xml @@ -4,7 +4,8 @@ - + + diff --git a/knowledge/org.argeo.support.odk/OSGI-INF/odkSubmissionServlet.xml b/knowledge/org.argeo.support.odk/OSGI-INF/odkSubmissionServlet.xml index e9153b4..1e1bcb1 100644 --- a/knowledge/org.argeo.support.odk/OSGI-INF/odkSubmissionServlet.xml +++ b/knowledge/org.argeo.support.odk/OSGI-INF/odkSubmissionServlet.xml @@ -7,4 +7,5 @@ + diff --git a/knowledge/org.argeo.support.odk/bnd.bnd b/knowledge/org.argeo.support.odk/bnd.bnd index 9db4e0c..0154985 100644 --- a/knowledge/org.argeo.support.odk/bnd.bnd +++ b/knowledge/org.argeo.support.odk/bnd.bnd @@ -1,9 +1,17 @@ -Import-Package:\ -org.osgi.service.http.context,\ -* +Require-Capability:\ +cms.datamodel;filter:="(name=entity)",\ +cms.datamodel;filter:="(name=xforms)" + +Provide-Capability:\ +cms.datamodel; name=odk; cnd=/org/argeo/support/odk/odk.cnd Service-Component:\ OSGI-INF/odkServletContext.xml,\ OSGI-INF/odkFormListServlet.xml,\ OSGI-INF/odkFormServlet.xml,\ OSGI-INF/odkSubmissionServlet.xml + +Import-Package:\ +org.osgi.service.http.context,\ +org.argeo.api,\ +* diff --git a/knowledge/org.argeo.support.odk/pom.xml b/knowledge/org.argeo.support.odk/pom.xml index 26177c9..69cc95e 100644 --- a/knowledge/org.argeo.support.odk/pom.xml +++ b/knowledge/org.argeo.support.odk/pom.xml @@ -14,9 +14,9 @@ jar - org.argeo.commons - org.argeo.cms - ${version.argeo-commons} + org.argeo.suite + org.argeo.suite.core + 2.1.16-SNAPSHOT diff --git a/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/OdkNames.java b/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/OdkNames.java new file mode 100644 index 0000000..fbb2087 --- /dev/null +++ b/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/OdkNames.java @@ -0,0 +1,7 @@ +package org.argeo.support.odk; + +/** Names related to ODK. */ +public interface OdkNames { + + public final static String H_HTML = "h:html"; +} diff --git a/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/OrxListType.java b/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/OrxListType.java new file mode 100644 index 0000000..c51484c --- /dev/null +++ b/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/OrxListType.java @@ -0,0 +1,27 @@ +package org.argeo.support.odk; + +import org.argeo.entity.JcrName; + +/** Types related to the http://openrosa.org/xforms/xformsList namespace. */ +public enum OrxListType implements JcrName { + xform; + + @Override + public String getPrefix() { + return prefix(); + } + + public static String prefix() { + return "orxList"; + } + + @Override + public String getNamespace() { + return namespace(); + } + + public static String namespace() { + return "http://openrosa.org/xforms/xformsList"; + } + +} diff --git a/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/odk.cnd b/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/odk.cnd new file mode 100644 index 0000000..0f6fcc8 --- /dev/null +++ b/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/odk.cnd @@ -0,0 +1,39 @@ + + + + + + +[orxList:xform] > mix:created, mix:lastModified, jcrx:csum, entity:form ++ h:html (odk:html) = odk:html + +[odk:head] ++ h:title (jcrx:xmlvalue) = jcrx:xmlvalue ++ xforms:model (odk:model) = odk:model + +[odk:body] > xforms:ui + + +[odk:html] > mix:referenceable ++ h:head (odk:head) = odk:head ++ h:body (odk:body) = odk:body + +[odk:model] > xforms:model ++ odk:setgeopoint (odk:setgeopoint) = odk:setgeopoint ++ xforms:itext (odk:itext) = odk:itext + +[odk:itext] ++ xforms:translation (odk:translation) = odk:translation * + +[odk:translation] +- lang (STRING) m +- default (STRING) ++ xforms:text (odk:text) = odk:text * + +[odk:text] +- id (STRING) m ++ xforms:value (jcrx:xmlvalue) = jcrx:xmlvalue + +[odk:setgeopoint] +- event (STRING) +- ref (STRING) diff --git a/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/servlet/OdkFormListServlet.java b/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/servlet/OdkFormListServlet.java index 8398c7f..c8a66bf 100644 --- a/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/servlet/OdkFormListServlet.java +++ b/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/servlet/OdkFormListServlet.java @@ -2,10 +2,23 @@ package org.argeo.support.odk.servlet; import java.io.IOException; import java.io.Writer; +import java.security.AccessControlContext; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; import java.util.Collections; import java.util.HashSet; import java.util.Set; +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Property; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.query.Query; +import javax.jcr.query.QueryResult; +import javax.security.auth.Subject; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -13,7 +26,14 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.argeo.api.NodeConstants; +import org.argeo.cms.servlet.ServletAuthUtils; +import org.argeo.entity.EntityType; +import org.argeo.jcr.Jcr; +import org.argeo.jcr.JcrUtils; +import org.argeo.jcr.JcrxApi; import org.argeo.support.odk.OdkForm; +import org.argeo.support.odk.OrxListType; /** Lists available forms. */ public class OdkFormListServlet extends HttpServlet { @@ -22,6 +42,11 @@ public class OdkFormListServlet extends HttpServlet { private Set odkForms = Collections.synchronizedSet(new HashSet<>()); + private DateTimeFormatter versionFormatter = DateTimeFormatter.ofPattern("YYYY-MM-dd-HHmm") + .withZone(ZoneId.from(ZoneOffset.UTC)); + + private Repository repository; + @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/xml; charset=utf-8"); @@ -32,26 +57,100 @@ public class OdkFormListServlet extends HttpServlet { int serverPort = req.getServerPort(); String protocol = serverPort == 443 || req.isSecure() ? "https" : "http"; + String pathInfo = req.getPathInfo(); + + Subject subject = Subject + .getSubject((AccessControlContext) req.getAttribute(AccessControlContext.class.getName())); + log.debug("SERVLET CONTEXT: " + subject); + + Session session = ServletAuthUtils.doAs(() -> Jcr.login(repository, NodeConstants.SYS_WORKSPACE), req); +// session = NodeUtils.openDataAdminSession(repository, NodeConstants.SYS_WORKSPACE); Writer writer = resp.getWriter(); writer.append(""); writer.append(""); - for (OdkForm form : odkForms) { - StringBuilder sb = new StringBuilder(); - sb.append(""); - sb.append("" + form.getFormId() + ""); - sb.append("" + form.getName() + ""); - sb.append("" + form.getVersion() + ""); - sb.append("" + form.getHash(null) + ""); - sb.append("" + form.getDescription() + ""); - sb.append("" + protocol + "://" + serverName - + (serverPort == 80 - || serverPort == 443 ? "" : ":" + serverPort) + "/api/odk/" + form.getFileName() - + ""); - sb.append(""); - String str = sb.toString(); - if (log.isDebugEnabled()) - log.debug(str); - writer.append(str); + boolean oldApproach = false; + if (oldApproach) { + try { + + Query query; + if (pathInfo == null) { +// query = session.getWorkspace().getQueryManager() +// .createQuery("SELECT * FROM [nt:unstructured]", Query.JCR_SQL2); + query = session.getWorkspace().getQueryManager() + .createQuery("SELECT * FROM [" + OrxListType.xform.get() + "]", Query.JCR_SQL2); + } else { + query = session.getWorkspace().getQueryManager() + .createQuery( + "SELECT node FROM [" + OrxListType.xform.get() + + "] AS node WHERE ISDESCENDANTNODE (node, '" + pathInfo + "')", + Query.JCR_SQL2); + } + QueryResult queryResult = query.execute(); + + NodeIterator nit = queryResult.getNodes(); +// log.debug(session.getUserID()); +// log.debug(session.getWorkspace().getName()); +// NodeIterator nit = session.getRootNode().getNodes(); +// while (nit.hasNext()) { +// log.debug(nit.nextNode()); +// } + while (nit.hasNext()) { + StringBuilder sb = new StringBuilder(); + Node node = nit.nextNode(); + if (node.isNodeType(OrxListType.xform.get())) { + sb.append(""); + sb.append("" + node.getNode("h:html").getIdentifier() + ""); + sb.append("" + Jcr.getTitle(node) + ""); + sb.append("" + versionFormatter.format(JcrUtils.getModified(node)) + ""); + sb.append("md5:" + JcrxApi.getChecksum(node, JcrxApi.MD5) + ""); + if (node.hasProperty(Property.JCR_DESCRIPTION)) + sb.append("" + node.getProperty(Property.JCR_DESCRIPTION).getString() + ""); + sb.append("" + protocol + "://" + serverName + + (serverPort == 80 || serverPort == 443 ? "" : ":" + serverPort) + "/api/odk/form/" + + node.getPath() + ""); + sb.append(""); + } else if (node.isNodeType(EntityType.formSet.get())) { + sb.append(""); + sb.append("" + node.getPath() + ""); + sb.append("" + node.getProperty(Property.JCR_TITLE).getString() + ""); + sb.append("" + protocol + "://" + serverName + + (serverPort == 80 || serverPort == 443 ? "" : ":" + serverPort) + "/api/odk/formList" + + node.getPath() + ""); + sb.append(""); + } + String str = sb.toString(); + if (!str.equals("")) { + if (log.isDebugEnabled()) + log.debug(str); + writer.append(str); + } + } + } catch (RepositoryException e) { + e.printStackTrace(); + // TODO error message + // resp.sendError(500); + } finally { + Jcr.logout(session); + } + + } else { + for (OdkForm form : odkForms) { + StringBuilder sb = new StringBuilder(); + sb.append(""); + sb.append("" + form.getFormId() + ""); + sb.append("" + form.getName() + ""); + sb.append("" + form.getVersion() + ""); + sb.append("" + form.getHash(null) + ""); + sb.append("" + form.getDescription() + ""); + sb.append("" + protocol + "://" + serverName + + (serverPort == 80 || serverPort == 443 ? "" : ":" + serverPort) + "/api/odk/form/" + + form.getFileName() + ""); + sb.append(""); + String str = sb.toString(); + if (log.isDebugEnabled()) + log.debug(str); + writer.append(str); + } } writer.append(""); } @@ -63,4 +162,9 @@ public class OdkFormListServlet extends HttpServlet { public void removeForm(OdkForm odkForm) { odkForms.remove(odkForm); } + + public void setRepository(Repository repository) { + this.repository = repository; + } + } diff --git a/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/servlet/OdkFormServlet.java b/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/servlet/OdkFormServlet.java index 3746da8..301e1bb 100644 --- a/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/servlet/OdkFormServlet.java +++ b/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/servlet/OdkFormServlet.java @@ -7,35 +7,59 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.FilenameUtils; +import org.argeo.cms.servlet.ServletAuthUtils; +import org.argeo.jcr.Jcr; import org.argeo.support.odk.OdkForm; +import org.argeo.support.odk.OdkNames; /** Retrieves a single form. */ public class OdkFormServlet extends HttpServlet { private static final long serialVersionUID = 7838305967987687370L; + private Repository repository; private Map odkForms = Collections.synchronizedMap(new HashMap<>()); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/xml; charset=utf-8"); - String path = req.getServletPath(); - String fileName = FilenameUtils.getName(path); - OdkForm form = odkForms.get(fileName); - if (form == null) - throw new IllegalArgumentException("No form named " + fileName + " was found"); - - byte[] buffer = new byte[1024]; - try (InputStream in = form.openStream(); OutputStream out = resp.getOutputStream();) { - int bytesRead; - while ((bytesRead = in.read(buffer)) != -1) - out.write(buffer, 0, bytesRead); + Session session = ServletAuthUtils.doAs(() -> Jcr.login(repository, null), req); + + String pathInfo = req.getPathInfo(); + + boolean oldApproach = false; + try { + if (!oldApproach) { + session.exportDocumentView(pathInfo + "/" + OdkNames.H_HTML, resp.getOutputStream(), true, false); + } else { + + String fileName = FilenameUtils.getName(pathInfo); + OdkForm form = odkForms.get(fileName); + if (form == null) + throw new IllegalArgumentException("No form named " + fileName + " was found"); + + byte[] buffer = new byte[1024]; + try (InputStream in = form.openStream(); OutputStream out = resp.getOutputStream();) { + int bytesRead; + while ((bytesRead = in.read(buffer)) != -1) + out.write(buffer, 0, bytesRead); + } + } + } catch (RepositoryException e) { + e.printStackTrace(); + // TODO error message + resp.sendError(500); + } finally { + Jcr.logout(session); } } @@ -47,4 +71,8 @@ public class OdkFormServlet extends HttpServlet { odkForms.remove(odkForm.getFileName()); } + public void setRepository(Repository repository) { + this.repository = repository; + } + } diff --git a/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/servlet/OdkServletContext.java b/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/servlet/OdkServletContext.java index 2c37edc..1711f2d 100644 --- a/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/servlet/OdkServletContext.java +++ b/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/servlet/OdkServletContext.java @@ -5,6 +5,7 @@ import javax.servlet.http.HttpServletResponse; import org.argeo.cms.servlet.PrivateWwwAuthServletContext; +/** OSK specific authentication (with additional headers).*/ public class OdkServletContext extends PrivateWwwAuthServletContext { @Override diff --git a/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/servlet/OdkSubmissionServlet.java b/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/servlet/OdkSubmissionServlet.java index 3a97580..e5f5a3f 100644 --- a/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/servlet/OdkSubmissionServlet.java +++ b/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/servlet/OdkSubmissionServlet.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; +import javax.jcr.Repository; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -26,6 +27,8 @@ public class OdkSubmissionServlet extends HttpServlet { private final static String XML_SUBMISSION_FILE = "xml_submission_file"; + private Repository repository; + @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { for (Part part : req.getParts()) { @@ -58,4 +61,9 @@ public class OdkSubmissionServlet extends HttpServlet { + "Form Received!" + ""); } + + public void setRepository(Repository repository) { + this.repository = repository; + } + } diff --git a/knowledge/org.argeo.support.xforms/.classpath b/knowledge/org.argeo.support.xforms/.classpath new file mode 100644 index 0000000..e801ebf --- /dev/null +++ b/knowledge/org.argeo.support.xforms/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/knowledge/org.argeo.support.xforms/.gitignore b/knowledge/org.argeo.support.xforms/.gitignore new file mode 100644 index 0000000..09e3bc9 --- /dev/null +++ b/knowledge/org.argeo.support.xforms/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/target/ diff --git a/knowledge/org.argeo.support.xforms/.project b/knowledge/org.argeo.support.xforms/.project new file mode 100644 index 0000000..3c50bfa --- /dev/null +++ b/knowledge/org.argeo.support.xforms/.project @@ -0,0 +1,28 @@ + + + org.argeo.support.xforms + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/knowledge/org.argeo.support.xforms/META-INF/.gitignore b/knowledge/org.argeo.support.xforms/META-INF/.gitignore new file mode 100644 index 0000000..4854a41 --- /dev/null +++ b/knowledge/org.argeo.support.xforms/META-INF/.gitignore @@ -0,0 +1 @@ +/MANIFEST.MF diff --git a/knowledge/org.argeo.support.xforms/bnd.bnd b/knowledge/org.argeo.support.xforms/bnd.bnd new file mode 100644 index 0000000..23c86a9 --- /dev/null +++ b/knowledge/org.argeo.support.xforms/bnd.bnd @@ -0,0 +1,5 @@ +Require-Capability:\ +cms.datamodel;filter:="(name=entity)" + +Provide-Capability:\ +cms.datamodel; name=xforms; cnd=/org/argeo/support/xforms/xforms.cnd diff --git a/knowledge/org.argeo.support.xforms/build.properties b/knowledge/org.argeo.support.xforms/build.properties new file mode 100644 index 0000000..34d2e4d --- /dev/null +++ b/knowledge/org.argeo.support.xforms/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/knowledge/org.argeo.support.xforms/pom.xml b/knowledge/org.argeo.support.xforms/pom.xml new file mode 100644 index 0000000..0d75c9a --- /dev/null +++ b/knowledge/org.argeo.support.xforms/pom.xml @@ -0,0 +1,22 @@ + + + 4.0.0 + + org.argeo.suite + knowledge + 2.1.16-SNAPSHOT + .. + + org.argeo.support.xforms + XForms support + jar + + + org.argeo.suite + org.argeo.suite.core + 2.1.16-SNAPSHOT + + + diff --git a/knowledge/org.argeo.support.xforms/src/org/argeo/support/xforms/xforms.cnd b/knowledge/org.argeo.support.xforms/src/org/argeo/support/xforms/xforms.cnd new file mode 100644 index 0000000..c24dbae --- /dev/null +++ b/knowledge/org.argeo.support.xforms/src/org/argeo/support/xforms/xforms.cnd @@ -0,0 +1,39 @@ + + +[xforms:model] ++ xforms:instance (xforms:instance) = xforms:instance * ++ xforms:bind (xforms:bind) = xforms:bind * ++ xforms:setvalue (xforms:setvalue) = xforms:setvalue * + +[xforms:instance] > nt:unstructured + +[xforms:bind] +- * (STRING) + +[xforms:setvalue] +- * (STRING) + +[xforms:select] > xforms:input ++ xforms:itemset (xforms:itemset) = xforms:itemset + +[xforms:itemset] +- nodeset (STRING) ++ xforms:label (jcrx:xmlvalue) = jcrx:xmlvalue ++ xforms:value (jcrx:xmlvalue) = jcrx:xmlvalue + +[xforms:ui] +- * (STRING) ++ xforms:label (jcrx:xmlvalue) = jcrx:xmlvalue * ++ xforms:hint (jcrx:xmlvalue) = jcrx:xmlvalue * ++ xforms:input (xforms:input) = xforms:input * ++ xforms:select (xforms:select) = xforms:select * ++ xforms:select1 (xforms:select) = xforms:select * ++ xforms:trigger (xforms:input) = xforms:input * ++ xforms:upload (xforms:input) = xforms:input * ++ xforms:group (xforms:ui) = xforms:ui * ++ xforms:repeat (xforms:ui) = xforms:ui * + +[xforms:input] +- * (STRING) ++ xforms:label (jcrx:xmlvalue) = jcrx:xmlvalue ++ xforms:hint (jcrx:xmlvalue) = jcrx:xmlvalue * diff --git a/knowledge/org.argeo.support.xforms/xsd/XForms-Schema.xsd b/knowledge/org.argeo.support.xforms/xsd/XForms-Schema.xsd new file mode 100644 index 0000000..6383f86 --- /dev/null +++ b/knowledge/org.argeo.support.xforms/xsd/XForms-Schema.xsd @@ -0,0 +1,858 @@ + + + + + + + + Attributes for _every_ element in XForms + + + + + + + + + + + + + + + + + + + + + + + + + instance container. + + + + + + + + + + + + submit info container. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Definition of bind container. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/knowledge/pom.xml b/knowledge/pom.xml index 4a8c550..91c2af3 100644 --- a/knowledge/pom.xml +++ b/knowledge/pom.xml @@ -11,6 +11,8 @@ Argeo Knowledge Components pom + org.argeo.support.xforms org.argeo.support.odk + org.argeo.support.geonames diff --git a/org.argeo.entity.api/bnd.bnd b/org.argeo.entity.api/bnd.bnd index a7d5dd1..ab46172 100644 --- a/org.argeo.entity.api/bnd.bnd +++ b/org.argeo.entity.api/bnd.bnd @@ -1,3 +1,5 @@ +Require-Capability:\ +cms.datamodel;filter:="(name=jcrx)" Provide-Capability:\ cms.datamodel; name=entity; cnd=/org/argeo/entity/entity.cnd diff --git a/org.argeo.entity.api/src/org/argeo/entity/EntityNames.java b/org.argeo.entity.api/src/org/argeo/entity/EntityNames.java index 9739471..f32c262 100644 --- a/org.argeo.entity.api/src/org/argeo/entity/EntityNames.java +++ b/org.argeo.entity.api/src/org/argeo/entity/EntityNames.java @@ -4,13 +4,23 @@ import org.argeo.naming.LdapAttrs; /** Constants used to name entity structures. */ public interface EntityNames { - final String ENTITY_DEFINITIONS_PATH = "/entity:entityDefinitions"; + final String FORM_BASE = "form"; + final String TERM_BASE = "term"; + + final String ENTITY_DEFINITIONS_PATH = "/entity"; + @Deprecated + final String TYPOLOGIES_PATH = "/" + TERM_BASE; + /** Administrative units. */ + final String ADM = "adm"; final String ENTITY_TYPE = "entity:type"; final String ENTITY_UID = "entity:uid"; + final String ENTITY_NAME = "entity:name"; // GENERIC CONCEPTS - /** The date which is clearly relevant for this entity. */ + /** The language which is relevant. */ + final String XML_LANG = "xml:lang"; + /** The date which is relevant. */ final String ENTITY_DATE = "entity:date"; final String ENTITY_RELATED_TO = "entity:relatedTo"; @@ -21,4 +31,10 @@ public interface EntityNames { final String SURNAME = LdapAttrs.sn.property(); final String EMAIL = LdapAttrs.mail.property(); + final String OU = LdapAttrs.ou.property(); + + // WGS84 + final String GEO_LAT = "geo:lat"; + final String GEO_LONG = "geo:long"; + final String GEO_ALT = "geo:alt"; } diff --git a/org.argeo.entity.api/src/org/argeo/entity/EntityType.java b/org.argeo.entity.api/src/org/argeo/entity/EntityType.java new file mode 100644 index 0000000..6548d75 --- /dev/null +++ b/org.argeo.entity.api/src/org/argeo/entity/EntityType.java @@ -0,0 +1,32 @@ +package org.argeo.entity; + +/** Types related to entities. */ +public enum EntityType implements JcrName { + // entity + entity, definition, + // typology + typologies, terms, term, + // form + form, formSet, + // ldap + person; + + @Override + public String getPrefix() { + return prefix(); + } + + public static String prefix() { + return "entity"; + } + + @Override + public String getNamespace() { + return namespace(); + } + + public static String namespace() { + return "http://www.argeo.org/ns/entity"; + } + +} diff --git a/org.argeo.entity.api/src/org/argeo/entity/EntityTypes.java b/org.argeo.entity.api/src/org/argeo/entity/EntityTypes.java index f4b3e5e..ef35147 100644 --- a/org.argeo.entity.api/src/org/argeo/entity/EntityTypes.java +++ b/org.argeo.entity.api/src/org/argeo/entity/EntityTypes.java @@ -1,6 +1,7 @@ package org.argeo.entity; /** Types related to entities. */ +@Deprecated public interface EntityTypes { final static String ENTITY_ENTITY = "entity:entity"; final static String ENTITY_DEFINITION = "entity:definition"; diff --git a/org.argeo.entity.api/src/org/argeo/entity/JcrName.java b/org.argeo.entity.api/src/org/argeo/entity/JcrName.java new file mode 100644 index 0000000..43057aa --- /dev/null +++ b/org.argeo.entity.api/src/org/argeo/entity/JcrName.java @@ -0,0 +1,26 @@ +package org.argeo.entity; + +/** Can be applied to {@link Enum}s in order to generate prefixed names. */ +public interface JcrName { + String name(); + + default String getPrefix() { + return null; + } + + default String getNamespace() { + return null; + } + + default String get() { + String prefix = getPrefix(); + return prefix != null ? prefix + ":" + name() : name(); + } + + default String withNamespace() { + String namespace = getNamespace(); + if (namespace == null) + throw new UnsupportedOperationException("No namespace is specified for " + getClass()); + return "{" + namespace + "}" + name(); + } +} diff --git a/org.argeo.entity.api/src/org/argeo/entity/entity.cnd b/org.argeo.entity.api/src/org/argeo/entity/entity.cnd index 67116cd..78fb8cc 100644 --- a/org.argeo.entity.api/src/org/argeo/entity/entity.cnd +++ b/org.argeo.entity.api/src/org/argeo/entity/entity.cnd @@ -1,28 +1,59 @@ - +// Standard namespaces + + +// see https://www.w3.org/2003/01/geo/ +// + + -[entity:entity] > mix:title, mix:created, mix:lastModified, mix:referenceable +[entity:entity] > mix:created, mix:referenceable mixin //- entity:uid (String) m // an implementation dependent UID for each entity //- entity:type (String) // the type of this entity -[entity:definition] > entity:composite, mix:title, mix:created, mix:lastModified, mix:referenceable -mixin +// +// ENTITY DEFINITION +// +[entity:definition] > entity:composite, mix:created, mix:lastModified, mix:referenceable +//- entity:type (String) multiple -[entity:part] -mixin +//[entity:part] -[entity:reference] -mixin +//[entity:reference] [entity:composite] -mixin orderable -+ * (entity:part) -+ * (entity:reference) -+ * (entity:composite) +//+ * (entity:part) +//+ * (entity:reference) +//+ * (entity:composite) + +// +// TYPOLOGY +// +[entity:typologies] ++ * (entity:terms) = entity:terms + +[entity:term] +orderable ++ * (entity:term) = entity:term * + +[entity:terms] > mix:referenceable +orderable ++ * (entity:term) = entity:term * + +// +// FORM +// +[entity:form] +mixin + +[entity:formSet] +mixin // LDAP-LIKE ENTITIES // A real person [entity:person] > entity:entity mixin +- ldap:sn (String) +- ldap:givenName (String) diff --git a/org.argeo.entity.core/src/org/argeo/entity/core/JcrEntityDefinition.java b/org.argeo.entity.core/src/org/argeo/entity/core/JcrEntityDefinition.java index 15fb812..f76eb63 100644 --- a/org.argeo.entity.core/src/org/argeo/entity/core/JcrEntityDefinition.java +++ b/org.argeo.entity.core/src/org/argeo/entity/core/JcrEntityDefinition.java @@ -32,8 +32,8 @@ public class JcrEntityDefinition implements EntityDefinition { defaultEditoryId = properties.get(EntityConstants.DEFAULT_EDITORY_ID); String definitionPath = EntityNames.ENTITY_DEFINITIONS_PATH + '/' + type; if (!adminSession.itemExists(definitionPath)) { - Node entityDefinition = JcrUtils.mkdirs(adminSession, definitionPath); - entityDefinition.addMixin(EntityTypes.ENTITY_DEFINITION); + Node entityDefinition = JcrUtils.mkdirs(adminSession, definitionPath, EntityTypes.ENTITY_DEFINITION); +// entityDefinition.addMixin(EntityTypes.ENTITY_DEFINITION); adminSession.save(); } initJcr(adminSession); diff --git a/org.argeo.suite.core/.project b/org.argeo.suite.core/.project index f47b00e..ab084af 100644 --- a/org.argeo.suite.core/.project +++ b/org.argeo.suite.core/.project @@ -20,6 +20,11 @@ + + org.eclipse.pde.ds.core.builder + + + org.eclipse.pde.PluginNature diff --git a/org.argeo.suite.core/OSGI-INF/maintenanceService.xml b/org.argeo.suite.core/OSGI-INF/maintenanceService.xml new file mode 100644 index 0000000..2d495c8 --- /dev/null +++ b/org.argeo.suite.core/OSGI-INF/maintenanceService.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.argeo.suite.core/bnd.bnd b/org.argeo.suite.core/bnd.bnd index d70ca8c..4887675 100644 --- a/org.argeo.suite.core/bnd.bnd +++ b/org.argeo.suite.core/bnd.bnd @@ -1,4 +1,10 @@ +Service-Component:\ +OSGI-INF/maintenanceService.xml Import-Package:\ +javax.transaction,\ +org.osgi.service.useradmin,\ +javax.jcr.nodetype,\ org.argeo.api,\ +org.argeo.entity,\ * \ No newline at end of file diff --git a/org.argeo.suite.core/build.properties b/org.argeo.suite.core/build.properties index 34d2e4d..6210e84 100644 --- a/org.argeo.suite.core/build.properties +++ b/org.argeo.suite.core/build.properties @@ -1,4 +1,5 @@ -source.. = src/ output.. = bin/ bin.includes = META-INF/,\ - . + .,\ + OSGI-INF/ +source.. = src/ diff --git a/org.argeo.suite.core/pom.xml b/org.argeo.suite.core/pom.xml index c6a7d4f..9c89ce5 100644 --- a/org.argeo.suite.core/pom.xml +++ b/org.argeo.suite.core/pom.xml @@ -25,5 +25,10 @@ org.argeo.cms ${version.argeo-commons} + + org.argeo.commons + org.argeo.maintenance + ${version.argeo-commons} + diff --git a/org.argeo.suite.core/src/org/argeo/suite/RankedObject.java b/org.argeo.suite.core/src/org/argeo/suite/RankedObject.java index f0165af..bfba46e 100644 --- a/org.argeo.suite.core/src/org/argeo/suite/RankedObject.java +++ b/org.argeo.suite.core/src/org/argeo/suite/RankedObject.java @@ -76,16 +76,16 @@ public class RankedObject { RankedObject rankedObject = new RankedObject<>(object, properties); if (!map.containsKey(key)) { map.put(key, rankedObject); - if (log.isDebugEnabled()) - log.debug( + if (log.isTraceEnabled()) + log.trace( "Added " + key + " as " + object.getClass().getName() + " with rank " + rankedObject.getRank()); return rankedObject; } else { RankedObject current = map.get(key); if (current.getRank() <= rankedObject.getRank()) { map.put(key, rankedObject); - if (log.isDebugEnabled()) - log.debug("Replaced " + key + " by " + object.getClass().getName() + " with rank " + if (log.isTraceEnabled()) + log.trace("Replaced " + key + " by " + object.getClass().getName() + " with rank " + rankedObject.getRank()); return rankedObject; } else { diff --git a/org.argeo.suite.core/src/org/argeo/suite/core/SuiteMaintenanceService.java b/org.argeo.suite.core/src/org/argeo/suite/core/SuiteMaintenanceService.java new file mode 100644 index 0000000..44d218c --- /dev/null +++ b/org.argeo.suite.core/src/org/argeo/suite/core/SuiteMaintenanceService.java @@ -0,0 +1,29 @@ +package org.argeo.suite.core; + +import java.io.IOException; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.argeo.entity.EntityNames; +import org.argeo.entity.EntityType; +import org.argeo.maintenance.AbstractMaintenanceService; + +/** Initialises 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(EntityNames.TERM_BASE)) { + rootNode.addNode(EntityNames.TERM_BASE, EntityType.typologies.get()); + modified = true; + } + if (modified) + adminSession.save(); + return modified; + } + +}