/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.manifoldcf.crawler.connectors.nuxeo; import java.io.IOException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.TimeZone; import org.apache.commons.lang.StringUtils; import org.apache.manifoldcf.agents.interfaces.RepositoryDocument; import org.apache.manifoldcf.agents.interfaces.ServiceInterruption; import org.apache.manifoldcf.core.interfaces.ConfigParams; import org.apache.manifoldcf.core.interfaces.IHTTPOutput; import org.apache.manifoldcf.core.interfaces.IPasswordMapperActivity; import org.apache.manifoldcf.core.interfaces.IPostParameters; import org.apache.manifoldcf.core.interfaces.IThreadContext; import org.apache.manifoldcf.core.interfaces.ManifoldCFException; import org.apache.manifoldcf.core.interfaces.Specification; import org.apache.manifoldcf.core.interfaces.SpecificationNode; import org.apache.manifoldcf.crawler.connectors.BaseRepositoryConnector; import org.apache.manifoldcf.crawler.connectors.nuxeo.model.Attachment; import org.apache.manifoldcf.crawler.connectors.nuxeo.model.DocumentManifold; import org.apache.manifoldcf.crawler.interfaces.IExistingVersions; import org.apache.manifoldcf.crawler.interfaces.IProcessActivity; import org.apache.manifoldcf.crawler.interfaces.IRepositoryConnector; import org.apache.manifoldcf.crawler.interfaces.ISeedingActivity; import org.nuxeo.client.api.NuxeoClient; import org.nuxeo.client.api.objects.Document; import org.nuxeo.client.api.objects.Documents; import org.nuxeo.client.internals.spi.NuxeoClientException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Lists; import com.google.common.collect.Maps; /** * * Nuxeo Repository Connector class * * @author David Arroyo Escobar <arroyoescobardavid@gmail.com> * */ public class NuxeoRepositoryConnector extends BaseRepositoryConnector { private static final String URI_DOCUMENT = "SELECT * FROM Document"; protected final static String ACTIVITY_READ = "read document"; // Configuration tabs private static final String NUXEO_SERVER_TAB_PROPERTY = "NuxeoRepositoryConnector.Server"; // Specification tabs private static final String CONF_DOMAINS_TAB_PROPERTY = "NuxeoRepositoryConnector.Domains"; private static final String CONF_DOCUMENTS_TYPE_TAB_PROPERTY = "NuxeoRepositoryConnector.DocumentsType"; private static final String CONF_DOCUMENT_PROPERTY = "NuxeoRepositoryConnector.Documents"; // Prefix for nuxeo configuration and specification parameters private static final String PARAMETER_PREFIX = "nuxeo_"; // Templates for Nuxeo configuration /** * Javascript to check the configuration parameters */ private static final String EDIT_CONFIG_HEADER_FORWARD = "editConfiguration_conf.js"; /** * Server edit tab template */ private static final String EDIT_CONFIG_FORWARD_SERVER = "editConfiguration_conf_server.html"; /** * Server view tab template */ private static final String VIEW_CONFIG_FORWARD = "viewConfiguration_conf.html"; // Templates for Nuxeo specification /** * Forward to the javascript to check the specification parameters for the * job */ private static final String EDIT_SPEC_HEADER_FORWARD = "editSpecification_conf.js"; /** * Forward to the template to edit domains for the job */ private static final String EDIT_SPEC_FORWARD_CONF_DOMAINS = "editSpecification_confDomains.html"; /** * Forward to the template to edit documents type for the job */ private static final String EDIT_SPEC_FORWARD_CONF_DOCUMENTS_TYPE = "editSpecification_confDocumentsType.html"; /** * Forward to the template to edit document properties for the job */ private static final String EDIT_SPEC_FORWARD_CONF_DOCUMENTS = "editSpecification_confDocuments.html"; /** * Forward to the template to view the specification parameters for the job */ private static final String VIEW_SPEC_FORWARD = "viewSpecification_conf.html"; protected long lastSessionFetch = -1L; protected static final long timeToRelease = 300000L; private Logger logger = LoggerFactory.getLogger(NuxeoRepositoryConnector.class); /* Nuxeo instance parameters */ protected String protocol = null; protected String host = null; protected String port = null; protected String path = null; protected String username = null; protected String password = null; protected NuxeoClient nuxeoClient = null; // Constructor public NuxeoRepositoryConnector() { super(); } void setNuxeoClient(NuxeoClient nuxeoClient) { this.nuxeoClient = nuxeoClient; } @Override public String[] getActivitiesList() { return new String[] { ACTIVITY_READ }; } @Override public String[] getBinNames(String documentIdenfitier) { return new String[] { host }; } /** CONFIGURATION CONNECTOR **/ @Override public void outputConfigurationHeader(IThreadContext threadContext, IHTTPOutput out, Locale locale, ConfigParams parameters, List<String> tabsArray) throws ManifoldCFException, IOException { // Server tab tabsArray.add(Messages.getString(locale, NUXEO_SERVER_TAB_PROPERTY)); Map<String, String> paramMap = new HashMap<String, String>(); // Fill in the parameters form each tab fillInServerConfigurationMap(paramMap, out, parameters); Messages.outputResourceWithVelocity(out, locale, EDIT_CONFIG_HEADER_FORWARD, paramMap, true); } @Override public void outputConfigurationBody(IThreadContext threadContext, IHTTPOutput out, Locale locale, ConfigParams parameters, String tabName) throws ManifoldCFException, IOException { // Call the Velocity tempaltes for each tab Map<String, String> paramMap = new HashMap<String, String>(); // Set the tab name paramMap.put("TabName", tabName); // Fill in the parameters fillInServerConfigurationMap(paramMap, out, parameters); // Server tab Messages.outputResourceWithVelocity(out, locale, EDIT_CONFIG_FORWARD_SERVER, paramMap, true); } private static void fillInServerConfigurationMap(Map<String, String> serverMap, IPasswordMapperActivity mapper, ConfigParams parameters) { String nuxeoProtocol = parameters.getParameter(NuxeoConfiguration.Server.PROTOCOL); String nuxeoHost = parameters.getParameter(NuxeoConfiguration.Server.HOST); String nuxeoPort = parameters.getParameter(NuxeoConfiguration.Server.PORT); String nuxeoPath = parameters.getParameter(NuxeoConfiguration.Server.PATH); String nuxeoUsername = parameters.getParameter(NuxeoConfiguration.Server.USERNAME); String nuxeoPassword = parameters.getObfuscatedParameter(NuxeoConfiguration.Server.PASSWORD); if (nuxeoProtocol == null) nuxeoProtocol = NuxeoConfiguration.Server.PROTOCOL_DEFAULT_VALUE; if (nuxeoHost == null) nuxeoHost = NuxeoConfiguration.Server.HOST_DEFAULT_VALUE; if (nuxeoPort == null) nuxeoPort = NuxeoConfiguration.Server.PORT_DEFAULT_VALUE; if (nuxeoPath == null) nuxeoPath = NuxeoConfiguration.Server.PATH_DEFAULT_VALUE; if (nuxeoUsername == null) nuxeoUsername = NuxeoConfiguration.Server.USERNAME_DEFAULT_VALUE; if (nuxeoPassword == null) nuxeoPassword = NuxeoConfiguration.Server.PASSWORD_DEFAULT_VALUE; else nuxeoPassword = mapper.mapPasswordToKey(nuxeoPassword); serverMap.put(PARAMETER_PREFIX + NuxeoConfiguration.Server.PROTOCOL, nuxeoProtocol); serverMap.put(PARAMETER_PREFIX + NuxeoConfiguration.Server.HOST, nuxeoHost); serverMap.put(PARAMETER_PREFIX + NuxeoConfiguration.Server.PORT, nuxeoPort); serverMap.put(PARAMETER_PREFIX + NuxeoConfiguration.Server.PATH, nuxeoPath); serverMap.put(PARAMETER_PREFIX + NuxeoConfiguration.Server.USERNAME, nuxeoUsername); serverMap.put(PARAMETER_PREFIX + NuxeoConfiguration.Server.PASSWORD, nuxeoPassword); } @Override public String processConfigurationPost(IThreadContext thredContext, IPostParameters variableContext, ConfigParams parameters) { String nuxeoProtocol = variableContext.getParameter(PARAMETER_PREFIX + NuxeoConfiguration.Server.PROTOCOL); if (nuxeoProtocol != null) parameters.setParameter(NuxeoConfiguration.Server.PROTOCOL, nuxeoProtocol); String nuxeoHost = variableContext.getParameter(PARAMETER_PREFIX + NuxeoConfiguration.Server.HOST); if (nuxeoHost != null) parameters.setParameter(NuxeoConfiguration.Server.HOST, nuxeoHost); String nuxeoPort = variableContext.getParameter(PARAMETER_PREFIX + NuxeoConfiguration.Server.PORT); if (nuxeoPort != null) parameters.setParameter(NuxeoConfiguration.Server.PORT, nuxeoPort); String nuxeoPath = variableContext.getParameter(PARAMETER_PREFIX + NuxeoConfiguration.Server.PATH); if (nuxeoPath != null) parameters.setParameter(NuxeoConfiguration.Server.PATH, nuxeoPath); String nuxeoUsername = variableContext.getParameter(PARAMETER_PREFIX + NuxeoConfiguration.Server.USERNAME); if (nuxeoUsername != null) parameters.setParameter(NuxeoConfiguration.Server.USERNAME, nuxeoUsername); String nuxeoPassword = variableContext.getParameter(PARAMETER_PREFIX + NuxeoConfiguration.Server.PASSWORD); if (nuxeoPassword != null) parameters.setObfuscatedParameter(NuxeoConfiguration.Server.PASSWORD, variableContext.mapKeyToPassword(nuxeoPassword)); return null; } @Override public void viewConfiguration(IThreadContext threadContext, IHTTPOutput out, Locale locale, ConfigParams parameters) throws ManifoldCFException, IOException { Map<String, String> paramMap = new HashMap<String, String>(); fillInServerConfigurationMap(paramMap, out, parameters); Messages.outputResourceWithVelocity(out, locale, VIEW_CONFIG_FORWARD, paramMap, true); } /** CONNECTION **/ @Override public void connect(ConfigParams configParams) { super.connect(configParams); protocol = params.getParameter(NuxeoConfiguration.Server.PROTOCOL); host = params.getParameter(NuxeoConfiguration.Server.HOST); port = params.getParameter(NuxeoConfiguration.Server.PORT); path = params.getParameter(NuxeoConfiguration.Server.PATH); username = params.getParameter(NuxeoConfiguration.Server.USERNAME); password = params.getObfuscatedParameter(NuxeoConfiguration.Server.PASSWORD); } @Override public void disconnect() throws ManifoldCFException { shutdownNuxeoClient(); protocol = null; host = null; port = null; path = null; username = null; password = null; super.disconnect(); } // Check the connection @Override public String check() throws ManifoldCFException { shutdownNuxeoClient(); initNuxeoClient(); try { nuxeoClient.repository().getDocumentRoot(); } catch (NuxeoClientException ex) { return "Connection failed: "+ex.getMessage(); } return super.check(); } /** * Initialize Nuxeo client using the configured parameters. * * @throws ManifoldCFException */ private void initNuxeoClient() throws ManifoldCFException { if (nuxeoClient == null) { if (StringUtils.isEmpty(protocol)) { throw new ManifoldCFException( "Parameter " + NuxeoConfiguration.Server.PROTOCOL + " required but not set"); } if (StringUtils.isEmpty(host)) { throw new ManifoldCFException("Parameter " + NuxeoConfiguration.Server.HOST + " required but not set"); } String url = getUrl(); nuxeoClient = new NuxeoClient(url, username, password); lastSessionFetch = System.currentTimeMillis(); } } /** * Shut down Nuxeo client */ private void shutdownNuxeoClient() { if (nuxeoClient != null) { nuxeoClient.shutdown(); nuxeoClient = null; lastSessionFetch = -1L; } } /** * Formatter URL * * @throws ManifoldCFException */ String getUrl() throws ManifoldCFException { int portInt; if (port != null && port.length() > 0) { try { portInt = Integer.parseInt(port); } catch (NumberFormatException formatException) { throw new ManifoldCFException("Bad number: " + formatException.getMessage(), formatException); } } else { if (protocol.toLowerCase(Locale.ROOT).equals("http")) { portInt = 80; } else { portInt = 443; } } String url = protocol + "://" + host + ":" + portInt + "/" + path; return url; } @Override public boolean isConnected() { return nuxeoClient != null; } @Override public void poll() throws ManifoldCFException { if (lastSessionFetch == -1L) { return; } long currentTime = System.currentTimeMillis(); if (currentTime > lastSessionFetch + timeToRelease) { shutdownNuxeoClient(); } } /** SEEDING **/ @Override public String addSeedDocuments(ISeedingActivity activities, Specification spec, String lastSeedVersion, long seedTime, int jobMode) throws ManifoldCFException, ServiceInterruption { initNuxeoClient(); try { int lastStart = 0; int defaultSize = 50; Boolean isLast = true; NuxeoSpecification ns = NuxeoSpecification.from(spec); List<String> domains = ns.getDomains(); List<String> documentsType = ns.getDocumentsType(); do { Documents docs = getDocsByDate(nuxeoClient, lastSeedVersion, domains, documentsType, defaultSize, lastStart); for (Document doc : docs.getDocuments()) { activities.addSeedDocument(doc.getUid()); } lastStart++; isLast = docs.getIsNextPageAvailable(); } while (isLast); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); sdf.setTimeZone(TimeZone.getTimeZone("GMT")); lastSeedVersion = sdf.format(new Date()); return lastSeedVersion; } catch (NuxeoClientException exception) { throw new ManifoldCFException("Failure during seeding: "+exception.getMessage(), exception); /* exception.printStackTrace(); long interruptionRetryTime = 5L * 60L * 1000L; String message = "Server appears down during seeding: " + exception.getMessage(); throw new ServiceInterruption(message, exception, System.currentTimeMillis() + interruptionRetryTime, -1L, 3, true); */ } } /** * * @param nuxeoClient * @param date * @param domains * @param documentsType * @param limit * @param start * @return Documents */ Documents getDocsByDate(NuxeoClient nuxeoClient, String date, List<String> domains, List<String> documentsType, int limit, int start) { String query = ""; if (date == null || date.isEmpty()) { SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); date = DATE_FORMAT.format(new Date(0)); } query = "dc:modified > '" + date + "'"; if (!domains.isEmpty()) { Iterator<String> itdom = domains.iterator(); query = String.format(" %s AND ( ecm:path STARTSWITH '/%s'", query, itdom.next()); while (itdom.hasNext()) { query = String.format("%s OR ecm:path STARTSWITH '/%s'", query, itdom.next()); } query = String.format("%s )", query); } if (!documentsType.isEmpty()) { Iterator<String> itDocTy = documentsType.iterator(); query = String.format(" %s AND ( ecm:primaryType = '%s'", query, itDocTy.next()); while (itDocTy.hasNext()) { query = String.format("%s OR ecm:primaryType = '%s'", query, itDocTy.next()); } query = String.format("%s )", query); } query = String.format(URI_DOCUMENT + " where %s ", query); nuxeoClient.header("X-NXDocumentProperties", "*"); Documents docs = nuxeoClient.repository().query(query, String.valueOf(limit), String.valueOf(start), null, null, null, null); return docs; } /** PROCESS DOCUMENTS **/ @Override public void processDocuments(String[] documentsIdentifieres, IExistingVersions statuses, Specification spec, IProcessActivity activities, int jobMode, boolean usesDefaultAuthority) throws ManifoldCFException, ServiceInterruption { initNuxeoClient(); for (int i = 0; i < documentsIdentifieres.length; i++) { String documentId = documentsIdentifieres[i]; String version = statuses.getIndexedVersionString(documentId); long startTime = System.currentTimeMillis(); ProcessResult pResult = null; boolean doLog = true; try { pResult = processDocument(documentId, spec, version, activities, doLog, Maps.<String, String> newHashMap()); } catch (NuxeoClientException exception) { throw new ManifoldCFException("Client exception: "+exception.getMessage(), exception); } catch (IOException exception) { long interruptionRetryTime = 5L * 60L * 1000L; String message = "Server appears down during seeding: " + exception.getMessage(); throw new ServiceInterruption(message, exception, System.currentTimeMillis() + interruptionRetryTime, -1L, 3, true); } finally { if (doLog) if (pResult != null && pResult.errorCode != null && !pResult.errorCode.isEmpty()) activities.recordActivity(new Long(startTime), ACTIVITY_READ, pResult.fileSize, documentId, pResult.errorCode, pResult.errorDecription, null); } } } /** * @param documentId * @param version * @param activities * @param doLog * @param newHashMap * @return */ private ProcessResult processDocument(String documentId, Specification spec, String version, IProcessActivity activities, boolean doLog, HashMap<String, String> extraProperties) throws ManifoldCFException, ServiceInterruption, IOException { DocumentManifold doc = new DocumentManifold(nuxeoClient.repository().fetchDocumentById(documentId)); return processDocumentInternal(doc, documentId, spec, version, activities, doLog, extraProperties); } /** * @param doc * @param documentId * @param version * @param activities * @param doLog * @param extraProperties * @return */ private ProcessResult processDocumentInternal(DocumentManifold doc, String manifoldDocumentIdentifier, Specification spec, String version, IProcessActivity activities, boolean doLog, HashMap<String, String> extraProperties) throws ManifoldCFException, ServiceInterruption, IOException { RepositoryDocument rd = new RepositoryDocument(); NuxeoSpecification ns = NuxeoSpecification.from(spec); String lastModified = doc.getDocument().getLastModified(); Date lastModifiedDate = null; if (lastModified != null) { DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); try { lastModifiedDate = formatter.parse(lastModified); } catch (Exception ex) { lastModifiedDate = new Date(0); } } int lenght = doc.getLenght(); if (doc.getDocument().getState() != null && doc.getDocument().getState().equalsIgnoreCase(DocumentManifold.DELETED)) { activities.deleteDocument(manifoldDocumentIdentifier); return new ProcessResult(lenght, "DELETED", ""); } if (!activities.checkDocumentNeedsReindexing(manifoldDocumentIdentifier, lastModified)) { return new ProcessResult(lenght, "RETAINED", ""); } if (doc.getDocument().getUid() == null) { activities.deleteDocument(manifoldDocumentIdentifier); return new ProcessResult(lenght, "DELETED", ""); } // Add respository document information rd.setMimeType(doc.getMimeType()); rd.setModifiedDate(lastModifiedDate); rd.setIndexingDate(new Date()); // Adding Document metadata Map<String, Object> docMetadata = doc.getMetadata(); for (Entry<String, Object> entry : docMetadata.entrySet()) { if (entry.getValue() instanceof List) { List<?> list = (List<?>) entry.getValue(); rd.addField(entry.getKey(), list.toArray(new String[list.size()])); } else { rd.addField(entry.getKey(), entry.getValue().toString()); } } if (ns.isProcessTags()) rd.addField("Tags", doc.getTags(nuxeoClient)); String documentUri = null; try { documentUri = getUrl() + "/nxpath/" + doc.getDocument().getRepositoryName() + doc.getDocument().getPath() + "@view_documents"; } catch (NuxeoClientException ex) { documentUri = doc.getDocument().getUid(); } // Set repository ACLs String[] permissions = doc.getPermissions(nuxeoClient); rd.setSecurityACL(RepositoryDocument.SECURITY_TYPE_DOCUMENT, permissions); rd.setSecurityDenyACL(RepositoryDocument.SECURITY_TYPE_DOCUMENT, new String[] { GLOBAL_DENY_TOKEN }); rd.setBinary(doc.getContent(), lenght); // Action activities.ingestDocumentWithException(manifoldDocumentIdentifier, lastModified, documentUri, rd); if (ns.isProcessAttachments()) { for (Attachment att : doc.getAttachments(nuxeoClient)) { RepositoryDocument att_rd = new RepositoryDocument(); String attDocumentUri = att.getUrl(); att_rd.setMimeType(att.getMime_type()); att_rd.setBinary(att.getData(), att.getLength()); if (lastModified != null) att_rd.setModifiedDate(lastModifiedDate); att_rd.setIndexingDate(new Date()); att_rd.addField(Attachment.ATT_KEY_NAME, att.getName()); att_rd.addField(Attachment.ATT_KEY_LENGTH, String.valueOf(att.getLength())); att_rd.addField(Attachment.ATT_KEY_DIGEST, att.getDigest()); att_rd.addField(Attachment.ATT_KEY_DIGEST_ALGORITHM, att.getDigestAlgorithm()); att_rd.addField(Attachment.ATT_KEY_ENCODING, att.getEncoding()); // Set repository ACLs att_rd.setSecurityACL(RepositoryDocument.SECURITY_TYPE_DOCUMENT, permissions); att_rd.setSecurityDenyACL(RepositoryDocument.SECURITY_TYPE_DOCUMENT, new String[] { GLOBAL_DENY_TOKEN }); activities.ingestDocumentWithException(manifoldDocumentIdentifier, attDocumentUri, lastModified, attDocumentUri, att_rd); } } return new ProcessResult(lenght, "OK", StringUtils.EMPTY); } private class ProcessResult { private long fileSize; private String errorCode; private String errorDecription; private ProcessResult(long fileSize, String errorCode, String errorDescription) { this.fileSize = fileSize; this.errorCode = errorCode; this.errorDecription = errorDescription; } } @Override public int getConnectorModel() { return IRepositoryConnector.MODEL_ADD_CHANGE_DELETE; } /** Specifications **/ @Override public void viewSpecification(IHTTPOutput out, Locale locale, Specification spec, int connectionSequenceNumber) throws ManifoldCFException, IOException { Map<String, Object> paramMap = new HashMap<String, Object>(); paramMap.put("SeqNum", Integer.toString(connectionSequenceNumber)); NuxeoSpecification ns = NuxeoSpecification.from(spec); paramMap.put(NuxeoConfiguration.Specification.DOMAINS.toUpperCase(), ns.getDomains()); paramMap.put(NuxeoConfiguration.Specification.DOCUMENTS_TYPE.toUpperCase(), ns.documentsType); paramMap.put(NuxeoConfiguration.Specification.PROCESS_TAGS.toUpperCase(), ns.isProcessTags().toString()); paramMap.put(NuxeoConfiguration.Specification.PROCESS_ATTACHMENTS.toUpperCase(), ns.isProcessAttachments().toString()); Messages.outputResourceWithVelocity(out, locale, VIEW_SPEC_FORWARD, paramMap); } @Override public String processSpecificationPost(IPostParameters variableContext, Locale locale, Specification ds, int connectionSequenceNumber) throws ManifoldCFException { String seqPrefix = "s" + connectionSequenceNumber + "_"; // DOMAINS String xc = variableContext.getParameter(seqPrefix + "domainscount"); if (xc != null) { // Delete all preconfigured domains int i = 0; while (i < ds.getChildCount()) { SpecificationNode sn = ds.getChild(i); if (sn.getType().equals(NuxeoConfiguration.Specification.DOMAINS)) { ds.removeChild(i); } else { i++; } } SpecificationNode domains = new SpecificationNode(NuxeoConfiguration.Specification.DOMAINS); ds.addChild(ds.getChildCount(), domains); int domainsCount = Integer.parseInt(xc); i = 0; while (i < domainsCount) { String domainDescription = "_" + Integer.toString(i); String domainOpName = seqPrefix + "domainop" + domainDescription; xc = variableContext.getParameter(domainOpName); if (xc != null && xc.equals("Delete")) { i++; continue; } String domainKey = variableContext.getParameter(seqPrefix + "domain" + domainDescription); SpecificationNode node = new SpecificationNode(NuxeoConfiguration.Specification.DOMAIN); node.setAttribute(NuxeoConfiguration.Specification.DOMAIN_KEY, domainKey); domains.addChild(domains.getChildCount(), node); i++; } String op = variableContext.getParameter(seqPrefix + "domainop"); if (op != null && op.equals("Add")) { String domainSpec = variableContext.getParameter(seqPrefix + "domain"); SpecificationNode node = new SpecificationNode(NuxeoConfiguration.Specification.DOMAIN); node.setAttribute(NuxeoConfiguration.Specification.DOMAIN_KEY, domainSpec); domains.addChild(domains.getChildCount(), node); } } // TYPE OF DOCUMENTS String xt = variableContext.getParameter(seqPrefix + "documentsTypecount"); if (xt != null) { // Delete all preconfigured type of documents int i = 0; while (i < ds.getChildCount()) { SpecificationNode sn = ds.getChild(i); if (sn.getType().equals(NuxeoConfiguration.Specification.DOCUMENTS_TYPE)) { ds.removeChild(i); } else { i++; } } SpecificationNode documentsType = new SpecificationNode(NuxeoConfiguration.Specification.DOCUMENTS_TYPE); ds.addChild(ds.getChildCount(), documentsType); int documentsTypeCount = Integer.parseInt(xt); i = 0; while (i < documentsTypeCount) { String documentTypeDescription = "_" + Integer.toString(i); String documentTypeOpName = seqPrefix + "documentTypeop" + documentTypeDescription; xt = variableContext.getParameter(documentTypeOpName); if (xt != null && xt.equals("Delete")) { i++; continue; } String documentTypeKey = variableContext .getParameter(seqPrefix + "documentType" + documentTypeDescription); SpecificationNode node = new SpecificationNode(NuxeoConfiguration.Specification.DOCUMENT_TYPE); node.setAttribute(NuxeoConfiguration.Specification.DOCUMENT_TYPE_KEY, documentTypeKey); documentsType.addChild(documentsType.getChildCount(), node); i++; } String op = variableContext.getParameter(seqPrefix + "documentTypeop"); if (op != null && op.equals("Add")) { String documentTypeSpec = variableContext.getParameter(seqPrefix + "documentType"); SpecificationNode node = new SpecificationNode(NuxeoConfiguration.Specification.DOCUMENT_TYPE); node.setAttribute(NuxeoConfiguration.Specification.DOCUMENT_TYPE_KEY, documentTypeSpec); documentsType.addChild(documentsType.getChildCount(), node); } } // TAGS SpecificationNode documents = new SpecificationNode(NuxeoConfiguration.Specification.DOCUMENTS); ds.addChild(ds.getChildCount(), documents); String processTags = variableContext.getParameter(seqPrefix + NuxeoConfiguration.Specification.PROCESS_TAGS); String processAttachments = variableContext .getParameter(seqPrefix + NuxeoConfiguration.Specification.PROCESS_ATTACHMENTS); if (processTags != null && !processTags.isEmpty()) { documents.setAttribute(NuxeoConfiguration.Specification.PROCESS_TAGS, String.valueOf(processTags)); } if (processAttachments != null && !processAttachments.isEmpty()) { documents.setAttribute(NuxeoConfiguration.Specification.PROCESS_ATTACHMENTS, String.valueOf(processAttachments)); } return null; } @Override public void outputSpecificationBody(IHTTPOutput out, Locale locale, Specification spec, int connectionSequenceNumber, int actualSequenceNumber, String tabName) throws ManifoldCFException, IOException { Map<String, Object> paramMap = new HashMap<String, Object>(); paramMap.put("TabName", tabName); paramMap.put("SeqNum", Integer.toString(connectionSequenceNumber)); paramMap.put("SelectedNum", Integer.toString(actualSequenceNumber)); NuxeoSpecification ns = NuxeoSpecification.from(spec); paramMap.put(NuxeoConfiguration.Specification.DOMAINS.toUpperCase(), ns.getDomains()); paramMap.put(NuxeoConfiguration.Specification.DOCUMENTS_TYPE.toUpperCase(), ns.getDocumentsType()); paramMap.put(NuxeoConfiguration.Specification.PROCESS_TAGS.toUpperCase(), ns.isProcessTags()); paramMap.put(NuxeoConfiguration.Specification.PROCESS_ATTACHMENTS.toUpperCase(), ns.isProcessAttachments()); Messages.outputResourceWithVelocity(out, locale, EDIT_SPEC_FORWARD_CONF_DOMAINS, paramMap); Messages.outputResourceWithVelocity(out, locale, EDIT_SPEC_FORWARD_CONF_DOCUMENTS_TYPE, paramMap); Messages.outputResourceWithVelocity(out, locale, EDIT_SPEC_FORWARD_CONF_DOCUMENTS, paramMap); } @Override public void outputSpecificationHeader(IHTTPOutput out, Locale locale, Specification spec, int connectionSequenceNumber, List<String> tabsArray) throws ManifoldCFException, IOException { tabsArray.add(Messages.getString(locale, CONF_DOMAINS_TAB_PROPERTY)); tabsArray.add(Messages.getString(locale, CONF_DOCUMENTS_TYPE_TAB_PROPERTY)); tabsArray.add(Messages.getString(locale, CONF_DOCUMENT_PROPERTY)); Map<String, Object> paramMap = new HashMap<String, Object>(); paramMap.put("SeqNum", Integer.toString(connectionSequenceNumber)); Messages.outputResourceWithVelocity(out, locale, EDIT_SPEC_HEADER_FORWARD, paramMap); } static class NuxeoSpecification { private List<String> domains; private List<String> documentsType; private Boolean processTags = false; private Boolean processAttahcments = false; public List<String> getDomains() { return this.domains; } public List<String> getDocumentsType() { return this.documentsType; } public Boolean isProcessTags() { return this.processTags; } public Boolean isProcessAttachments() { return this.processAttahcments; } /** * @param spec * @return */ public static NuxeoSpecification from(Specification spec) { NuxeoSpecification ns = new NuxeoSpecification(); ns.domains = Lists.newArrayList(); ns.documentsType = Lists.newArrayList(); for (int i = 0, len = spec.getChildCount(); i < len; i++) { SpecificationNode sn = spec.getChild(i); if (sn.getType().equals(NuxeoConfiguration.Specification.DOMAINS)) { for (int j = 0, sLen = sn.getChildCount(); j < sLen; j++) { SpecificationNode spectNode = sn.getChild(j); if (spectNode.getType().equals(NuxeoConfiguration.Specification.DOMAIN)) { ns.domains.add(spectNode.getAttributeValue(NuxeoConfiguration.Specification.DOMAIN_KEY)); } } } else if (sn.getType().equals(NuxeoConfiguration.Specification.DOCUMENTS_TYPE)) { for (int j = 0, sLen = sn.getChildCount(); j < sLen; j++) { SpecificationNode spectNode = sn.getChild(j); if (spectNode.getType().equals(NuxeoConfiguration.Specification.DOCUMENT_TYPE)) { ns.documentsType.add( spectNode.getAttributeValue(NuxeoConfiguration.Specification.DOCUMENT_TYPE_KEY)); } } } else if (sn.getType().equals(NuxeoConfiguration.Specification.DOCUMENTS)) { String procTags = sn.getAttributeValue(NuxeoConfiguration.Specification.PROCESS_TAGS); ns.processTags = Boolean.valueOf(procTags); String procAtt = sn.getAttributeValue(NuxeoConfiguration.Specification.PROCESS_ATTACHMENTS); ns.processAttahcments = Boolean.valueOf(procAtt); } } return ns; } } }