added docs; logging; prep for maven central

This commit is contained in:
Brian Long 2022-10-10 22:14:02 -04:00
parent dd9d5735bf
commit 99d76df708
34 changed files with 1447 additions and 105 deletions

185
pom.xml
View File

@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.inteligr8.alfresco</groupId>
@ -11,8 +10,19 @@
<packaging>maven-plugin</packaging>
<name>A Maven plugin for Alfresco Process Services model portability</name>
<description>Generate Alfresco Module Packages (AMP) files in a way simialr to WAR files</description>
<url>https://bitbucket.org/inteligr8/amp-maven-plugin</url>
<licenses>
<license>
<name>GNU GENERAL PUBLIC LICENSE, Version 3, 29 June 2007</name>
<url>https://www.gnu.org/licenses/lgpl-3.0.txt</url>
</license>
</licenses>
<scm>
<connection>scm:git:https://bitbucket.org/inteligr8/aps-model-maven-plugin.git</connection>
<developerConnection>scm:git:git@bitbucket.org:inteligr8/aps-model-maven-plugin.git</developerConnection>
<url>https://bitbucket.org/inteligr8/aps-model-maven-plugin</url>
</scm>
<organization>
@ -41,14 +51,12 @@
<dependency>
<groupId>com.inteligr8.alfresco</groupId>
<artifactId>aps-public-rest-api</artifactId>
<version>2.0.1</version>
<classifier>aps1</classifier>
<version>2.0.3-aps1</version>
</dependency>
<dependency>
<groupId>com.inteligr8.alfresco</groupId>
<artifactId>aps-public-rest-client</artifactId>
<version>2.0.1</version>
<classifier>jersey</classifier>
<version>2.0.2-jersey</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
@ -109,10 +117,36 @@
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-invoker-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<projectsDirectory>${basedir}/src/it</projectsDirectory>
<cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
<localRepositoryPath>${project.build.directory}/it-repo</localRepositoryPath>
<mavenHome>${env.MAVEN_HOME}</mavenHome>
<debug>true</debug>
<skipInvocation>${skipTests}</skipInvocation>
<properties>
<project.main.basedir>${basedir}</project.main.basedir>
<aps-model.baseUrl>${aps-model.baseUrl}</aps-model.baseUrl>
<aps-model.authType>${aps-model.authType}</aps-model.authType>
<aps-model.basicAuth.mavenServerId>${aps-model.basicAuth.mavenServerId}</aps-model.basicAuth.mavenServerId>
<aps-model.appName>${aps-model.appName}</aps-model.appName>
<aps-model.share.editors>${aps-model.share.editors}</aps-model.share.editors>
<aps-model.share.readers>${aps-model.share.readers}</aps-model.share.readers>
<aps-model.share.app.editors>${aps-model.share.app.editors}</aps-model.share.app.editors>
</properties>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.6.0</version>
<version>3.6.1</version>
<configuration>
<goalPrefix>aps-model</goalPrefix>
</configuration>
@ -143,55 +177,29 @@
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-invoker-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<projectsDirectory>${basedir}/src/it</projectsDirectory>
<cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
<localRepositoryPath>${project.build.directory}/it-repo</localRepositoryPath>
<mavenHome>${env.MAVEN_HOME}</mavenHome>
<debug>true</debug>
<skipInvocation>${skipTests}</skipInvocation>
<properties>
<project.main.basedir>${basedir}</project.main.basedir>
<aps-model.baseUrl>${aps-model.baseUrl}</aps-model.baseUrl>
<aps-model.authType>${aps-model.authType}</aps-model.authType>
<aps-model.basicAuth.mavenServerId>${aps-model.basicAuth.mavenServerId}</aps-model.basicAuth.mavenServerId>
<aps-model.appName>${aps-model.appName}</aps-model.appName>
<aps-model.share.editors>${aps-model.share.editors}</aps-model.share.editors>
<aps-model.share.readers>${aps-model.share.readers}</aps-model.share.readers>
<aps-model.share.app.editors>${aps-model.share.app.editors}</aps-model.share.app.editors>
</properties>
</configuration>
<executions>
<execution>
<id>run-its</id>
<goals>
<goal>install</goal>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<id>javadoc</id>
<phase>package</phase>
<goals><goal>jar</goal></goals>
<configuration>
<show>public</show>
<skip>true</skip>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>run-its</id>
<build>
<plugins>
<plugin>
<artifactId>maven-invoker-plugin</artifactId>
<executions>
<execution>
<id>run-its</id>
<goals>
<goal>install</goal>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>run-it-1</id>
<activation>
@ -203,10 +211,9 @@
<plugins>
<plugin>
<artifactId>maven-invoker-plugin</artifactId>
<version>3.2.2</version>
<executions>
<execution>
<id>run-its</id>
<id>run-it-1</id>
<goals>
<goal>install</goal>
<goal>run</goal>
@ -222,22 +229,56 @@
</plugins>
</build>
</profile>
<profile>
<id>ossrh-release</id>
<build>
<plugins>
<plugin>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>source</id>
<phase>package</phase>
<goals><goal>jar-no-fork</goal></goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<id>javadoc</id>
<phase>package</phase>
<goals><goal>jar</goal></goals>
<configuration>
<show>public</show>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-gpg-plugin</artifactId>
<executions>
<execution>
<id>sign</id>
<phase>verify</phase>
<goals><goal>sign</goal></goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.13</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<repositories>
<repository>
<id>inteligr8-releases</id>
<name>Inteligr8 Releases</name>
<url>https://repos.inteligr8.com/nexus/repository/inteligr8-public</url>
</repository>
</repositories>
<distributionManagement>
<repository>
<id>inteligr8-releases</id>
<name>Inteligr8 Releases</name>
<url>https://repos.inteligr8.com/nexus/repository/inteligr8-public</url>
</repository>
</distributionManagement>
</project>

View File

@ -1,13 +1,48 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.crawler;
/**
* An interface for APS App export transformation implementations.
*
* An APS App export is a ZIP file that always contains an APS App JSON file.
* It may also contain many process XML/JSON files, form JSON files, thumbnail
* images, and more.
*
* @author brian@inteligr8.com
*/
public interface ApsAppCrawlable {
/**
* @return A file transformer for APS App JSON files.
*/
ApsFileTransformer getAppJsonTransformer();
/**
* @return A file transformer for APS Process JSON files.
*/
ApsFileTransformer getProcessJsonTransformer();
/**
* @return A file transformer for APS Process BPMN (XML) files.
*/
ApsFileTransformer getProcessBpmnTransformer();
/**
* @return A file transformer for APS Form JSON files.
*/
ApsFileTransformer getFormJsonTransformer();
}

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.crawler;
import java.io.File;
@ -11,6 +25,12 @@ import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A class that implements a APS App export crawler. The crawler does not
* directly perform any transformations. Those are handled through a callback.
*
* @author brian@inteligr8.com
*/
public class ApsAppCrawler {
private final Logger logger = LoggerFactory.getLogger(ApsAppCrawler.class);
@ -20,27 +40,39 @@ public class ApsAppCrawler {
private final File appDescriptor;
private final boolean failOnIntegrityViolation;
/**
* @param apsAppName A name for the APS App.
* @param apsAppDirectory A directory to the unpacked APS App export.
* @param failOnIntegrityViolation true to fail on file integrity issues; false to log warnings.
*/
public ApsAppCrawler(String apsAppName, File apsAppDirectory, boolean failOnIntegrityViolation) {
this.appName = apsAppName;
this.appDirectory = apsAppDirectory;
this.failOnIntegrityViolation = failOnIntegrityViolation;
this.appDescriptor = this.validateDescriptor(appDirectory);
this.appDescriptor = this.validateDescriptor();
if (this.logger.isDebugEnabled())
this.logger.debug("APS App descriptor found: " + this.appDescriptor);
}
protected File validateDescriptor(File appDirectory) {
File appDescriptor = new File(appDirectory, this.appName + ".json");
/**
* @return A file handle to the root APS App JSON (configuration) file.
*/
protected File validateDescriptor() {
File appDescriptor = new File(this.appDirectory, this.appName + ".json");
if (!appDescriptor.exists())
throw new IllegalStateException("The APS App descriptor could not be found: " + appDescriptor);
throw new IllegalStateException("The APS App descriptor could not be found: " + this.appDescriptor);
if (!appDescriptor.isFile())
throw new IllegalStateException("The APS App descriptor is not a file: " + appDescriptor);
throw new IllegalStateException("The APS App descriptor is not a file: " + this.appDescriptor);
return appDescriptor;
}
/**
* @param crawlable A crawlable implementation; the callback for potential transformations.
* @throws IOException A file access exception occurred.
*/
public void execute(ApsAppCrawlable crawlable) throws IOException {
this.logger.info("Crawling APS App ...");
@ -83,7 +115,7 @@ public class ApsAppCrawler {
}
String modelName = matcher.group(1);
Long modelId = new Long(matcher.group(2));
Long modelId = Long.valueOf(matcher.group(2));
this.logger.trace("Transforming model {} ID: {}", modelName, modelId);
this.transform(transformer, modelFile, modelName, modelId);

View File

@ -1,10 +1,39 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.crawler;
import java.io.File;
import java.io.IOException;
/**
* This interface provides a common method for transforming various files in an
* exported APS App.
*
* @author brian@inteligr8.com
*/
public interface ApsFileTransformer {
/**
* This method transforms the specified file which should be referred to
* with the specified name and ID.
*
* @param file A model file.
* @param modelName The target model name.
* @param modelId The target model ID.
* @throws IOException An I/O related exception has occurred during transformation.
*/
void transformFile(File file, String modelName, Long modelId) throws IOException;
}

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.goal;
import org.apache.maven.execution.MavenSession;
@ -8,6 +22,14 @@ import com.inteligr8.alfresco.activiti.ApsClientJerseyConfiguration;
import com.inteligr8.alfresco.activiti.ApsClientJerseyImpl;
import com.inteligr8.alfresco.activiti.ApsPublicRestApiJerseyImpl;
/**
* This class adds APS addressbility to extending goals.
*
* This is a common need for several goals in this library, as most of those
* goals will need to call an APS service to perform their work.
*
* @author brian@inteligr8.com
*/
public abstract class ApsAddressibleGoal extends DisablableGoal {
@Parameter( defaultValue = "${session}", readonly = true )
@ -36,6 +58,14 @@ public abstract class ApsAddressibleGoal extends DisablableGoal {
private ApsPublicRestApiJerseyImpl api;
/**
* Retrieves an APS client configuration.
*
* The configuration is built based on the properties injected into this
* class. It supports either `BASIC` or `OAuth` based authentication.
*
* @return An APS client configuration.
*/
public ApsClientJerseyConfiguration getApsClientConfiguration() {
this.getLog().debug("Configuring APS to URL: " + this.activitiAppBaseUrl);
ApsClientJerseyConfiguration config = new ApsClientJerseyConfiguration();
@ -86,6 +116,9 @@ public abstract class ApsAddressibleGoal extends DisablableGoal {
return config;
}
/**
* @return An APS API instance.
*/
public synchronized ApsPublicRestApiJerseyImpl getApsApi() {
if (this.api == null) {
ApsClientJerseyConfiguration config = this.getApsClientConfiguration();

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.goal;
import java.util.HashMap;
@ -13,11 +27,28 @@ import com.inteligr8.alfresco.activiti.model.Datum;
import com.inteligr8.alfresco.activiti.model.ResultListDataRepresentation;
import com.inteligr8.alfresco.activiti.model.Tenant;
/**
* This class adds the APS App name to APS addressibility to extending goals.
*
* Only use this class if your goal needs both the APS name and an APS service
* client. You can use `ApsAppGoal` or `ApsAddressibleGoal` if you only need
* one of those capabilities.
*
* @author brian@inteligr8.com
*/
public abstract class ApsAppAccessibleGoal extends ApsAddressibleGoal {
@Parameter( property = "aps-model.appName", required = true )
protected String apsAppName;
/**
* This method makes the appropriate service calls to find the first APS
* tenant ID from the configured APS service.
*
* This method does not cache the result.
*
* @return An APS tenant ID; null only if there are no tenants.
*/
protected Long findTenantId() {
List<Tenant> tenants = this.getApsApi().getAdminApi().getTenants();
if (tenants == null || tenants.isEmpty())
@ -25,6 +56,14 @@ public abstract class ApsAppAccessibleGoal extends ApsAddressibleGoal {
return tenants.iterator().next().getId();
}
/**
* This method makes the appropriate service calls to find all the APS
* Apps, returning them as a map of names to IDs.
*
* This method does not cache the result.
*
* @return A map of APS App names to their respective IDs; may be empty; never null.
*/
protected Map<String, Long> findAppNameIds() {
ApsPublicRestApiJerseyImpl api = this.getApsApi();
@ -42,10 +81,31 @@ public abstract class ApsAppAccessibleGoal extends ApsAddressibleGoal {
return apps;
}
/**
* This method makes the appropriate service calls to find the APS App by
* the configured APS App name.
*
* This method does not cache the result.
*
* @param failOnNotFound true to fail if not found; false to return null.
* @return An APS App ID; null if not found.
* @throws MojoExecutionException The APS App could not be found.
*/
protected Long findAppId(boolean failOnNotFound) throws MojoExecutionException {
return this.findAppIdByName(this.apsAppName, failOnNotFound);
}
/**
* This method makes the appropriate service calls to find an APS App by
* the specified APS App name.
*
* This method does not cache the result.
*
* @param apsName An APS App name.
* @param failOnNotFound true to fail if not found; false to return null.
* @return An APS App ID; null if not found.
* @throws MojoExecutionException The APS App could not be found.
*/
protected Long findAppIdByName(String appName, boolean failOnNotFound) throws MojoExecutionException {
Map<String, Long> apps = this.findAppNameIds();
Long appId = apps.get(this.apsAppName);

View File

@ -1,7 +1,26 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.goal;
import org.apache.maven.plugins.annotations.Parameter;
/**
* This class adds the APS App name to extending goals.
*
* @author brian@inteligr8.com
*/
public abstract class ApsAppGoal extends DisablableGoal {
@Parameter( property = "aps-model.appName", required = true )

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.goal;
import org.apache.maven.plugin.MojoExecutionException;
@ -7,6 +21,15 @@ import org.codehaus.plexus.component.annotations.Component;
import com.inteligr8.alfresco.activiti.model.AppVersion;
/**
* A class that implements an APS service information goal.
*
* This goal will simply output the APS edition and version to the Maven output
* at the `INFO` level. It is a great way to test your connection
* configuration and network accessibility of the service.
*
* @author brian@inteligr8.com
*/
@Mojo( name = "aps-info", threadSafe = true )
@Component( role = org.apache.maven.plugin.Mojo.class )
public class ApsInfoGoal extends ApsAddressibleGoal {

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.goal;
import java.util.Arrays;
@ -24,6 +38,17 @@ import com.inteligr8.alfresco.activiti.model.SharePermission;
import com.inteligr8.alfresco.activiti.model.Tenant;
import com.inteligr8.maven.aps.modeling.util.Index;
/**
* A class that implements a way to 'share' APS models.
*
* All APS models are automatically owned by the person that creates them. The
* model is then not viewable or editable by anyone else, except for APS
* administrators. This class provides a way to automatically 'share' the
* synchronized models to groups or individual users. The 'share' may have
* readonly or editing capabilities, as configured.
*
* @author brian@inteligr8.com
*/
@Mojo( name = "share-models", threadSafe = true )
@Component( role = org.apache.maven.plugin.Mojo.class )
public class ApsShareGoal extends ApsAddressibleGoal {

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.goal;
import org.apache.maven.plugin.AbstractMojo;
@ -5,6 +19,10 @@ import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Parameter;
/**
* This class adds enable/disable capability to any goal. It uses the standard
* 'skip' terminology.
*/
public abstract class DisablableGoal extends AbstractMojo {
@Parameter( property = "aps-model.skip", required = true, defaultValue = "false" )
@ -24,6 +42,14 @@ public abstract class DisablableGoal extends AbstractMojo {
this.executeEnabled();
}
/**
* Identical to the `AbstractMojo.execute()` method, but it is only called
* when this is enabled.
*
* @throws MojoExecutionException The goal failed to execute.
* @throws MojoFailureException The goal failed whiling executing.
* @see org.apache.maven.plugin.AbstractMojo.execute()
*/
public abstract void executeEnabled() throws MojoExecutionException, MojoFailureException;
}

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.goal;
import java.io.File;
@ -12,6 +26,15 @@ import org.codehaus.plexus.component.annotations.Component;
import com.inteligr8.alfresco.activiti.ApsPublicRestApiJerseyImpl;
/**
* A class that implements an APS service download goal.
*
* This goal will simply download the APS App with the specified name from the
* specified APS service. The downloaded APS App will remain packed (zipped).
* If a file exists with a conflicting name, it will be overwritten.
*
* @author brian@inteligr8.com
*/
@Mojo( name = "download-app", threadSafe = true )
@Component( role = org.apache.maven.plugin.Mojo.class )
public class DownloadAppGoal extends ApsAppAccessibleGoal {

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.goal;
import java.io.BufferedInputStream;
@ -18,6 +32,15 @@ import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.codehaus.plexus.component.annotations.Component;
/**
* A class that implements an APS App packaging goal.
*
* This goal will simply pack (zip) a folder containing an APS App file
* structure. If a file exists with a conflicting name, it will be
* overwritten.
*
* @author brian@inteligr8.com
*/
@Mojo( name = "pack-app", threadSafe = true )
@Component( role = org.apache.maven.plugin.Mojo.class )
public class PackAppGoal extends ApsAppGoal {

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.goal;
import java.io.IOException;
@ -11,6 +25,14 @@ import org.codehaus.plexus.component.annotations.Component;
import com.inteligr8.alfresco.activiti.ApsPublicRestApiJerseyImpl;
import com.inteligr8.alfresco.activiti.model.AppDefinitionPublishRepresentation;
/**
* A class that implements an APS Service publish goal.
*
* This goal will simply attempt to publish an existing APS App using the APS
* Service. It is typically used in conjuection with the `upload-app` goal.
*
* @author brian@inteligr8.com
*/
@Mojo( name = "publish-app", threadSafe = true )
@Component( role = org.apache.maven.plugin.Mojo.class )
public class PublishAppGoal extends ApsAppAccessibleGoal {

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.goal;
import java.io.File;
@ -13,6 +27,20 @@ import org.codehaus.plexus.component.annotations.Component;
import com.inteligr8.maven.aps.modeling.crawler.ApsAppCrawler;
import com.inteligr8.maven.aps.modeling.translator.ApsAppTranslator;
/**
* A class that implements an APS App translation goal.
*
* This goal will translate all the JSON and XML files in an APS App to match
* the environment referenced by the specified APS App. This relies on all APS
* model elements (apps, processes, and forms) to have unique names. The names
* of those mdoel elements are used to remap IDs between environments.
*
* APS does not enforce a unique name constraint. But it is good practice to
* avoid using the same name anyhow. This plugin will just make you do it. It
* will error if a duplicate is detected.
*
* @author brian@inteligr8.com
*/
@Mojo( name = "translate-app", threadSafe = true )
@Component( role = org.apache.maven.plugin.Mojo.class )
public class TranslateAppGoal extends ApsAppAccessibleGoal {

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.goal;
import java.io.BufferedInputStream;
@ -29,6 +43,15 @@ import com.inteligr8.maven.aps.modeling.crawler.ApsAppCrawler;
import com.inteligr8.maven.aps.modeling.normalizer.ApsAppNormalizer;
import com.inteligr8.maven.aps.modeling.util.ModelUtil;
/**
* A class that implements an APS App unpackaging goal.
*
* This goal will simply unpack (unzip) an APS App export into a folder. If a
* folder of the APS App name already exists, it will be cleared before the
* export is unpacked into it.
*
* @author brian@inteligr8.com
*/
@Mojo( name = "unpack-app", threadSafe = true )
@Component( role = org.apache.maven.plugin.Mojo.class )
public class UnpackAppGoal extends ApsAppGoal {

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.goal;
import java.io.BufferedInputStream;
@ -16,6 +30,16 @@ import com.inteligr8.alfresco.activiti.ApsPublicRestApiJerseyImpl;
import com.inteligr8.alfresco.activiti.model.AppDefinitionUpdateResultRepresentation;
import com.inteligr8.alfresco.activiti.model.FileMultipartJersey;
/**
* A class that implements an APS service upload goal.
*
* This goal will simply upload an APS App package with the specified name to
* the specified APS service. Any IDs specified in the uploaded package must
* match existing IDs for them to properly version. That is the main purpose
* of this plugin and can be achieved using the 'translate-app' goal.
*
* @author brian@inteligr8.com
*/
@Mojo( name = "upload-app", threadSafe = true )
@Component( role = org.apache.maven.plugin.Mojo.class )
public class UploadAppGoal extends ApsAppAccessibleGoal {

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.normalizer;
import java.io.File;
@ -13,12 +27,30 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import com.inteligr8.maven.aps.modeling.util.ApsModelArrayNodeSorter;
import com.inteligr8.maven.aps.modeling.util.ModelUtil;
/**
* This class implements an APS App JSON configuration file normalizer.
*
* This will remove the 'lastUpdated' date of each defined process model. It
* will also order the process 'models' by their respective 'name' values.
*
* @author brian@inteligr8.com
*/
public class ApsAppJsonNormalizer implements ApsFileNormalizer {
private final Logger logger = LoggerFactory.getLogger(ApsAppJsonNormalizer.class);
private final boolean enableSorting;
/**
* This constructor initializes the default normalizer with or without
* sorting.
*
* The sorting feature is available for a better "diff" experience. If
* you intend to commit the APS App configurations to Git, you will want to
* enable sorting.
*
* @param enableSorting true to re-order JSON objects; false to keep as-is.
*/
public ApsAppJsonNormalizer(boolean enableSorting) {
this.enableSorting = enableSorting;
}

View File

@ -1,12 +1,54 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.normalizer;
import com.inteligr8.maven.aps.modeling.crawler.ApsAppCrawlable;
import com.inteligr8.maven.aps.modeling.crawler.ApsFileTransformer;
/**
* This class defines an APS App package normalizer.
*
* An APS App package is a ZIP file that contains multiple files in a
* predictable folder hierachy with predictable file names. It is effectively
* an APS App interchange format specification.
*
* A package must have at least a single configuration file at the root of the
* ZIP package in the JSON format. It must be named the APS App name. That
* file will then reference all the model elements contained in the ZIP. Any
* model elements not referenced will simply be ignored by APS and by this
* plugin.
*
* This class has methods that provide normalizer for all the various model
* elements in an APS App package.
*
* @author brian@inteligr8.com
*/
public class ApsAppNormalizer implements ApsAppCrawlable {
private final boolean enableSorting;
/**
* This constructor initializes the default normalizer with or without
* sorting.
*
* The sorting feature is available for a better "diff" experience. If
* you intend to commit the APS App configurations to Git, you will want to
* enable sorting.
*
* @param enableSorting true to re-order JSON objects; false to keep as-is.
*/
public ApsAppNormalizer(boolean enableSorting) {
this.enableSorting = enableSorting;
}

View File

@ -1,7 +1,33 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.normalizer;
import java.io.File;
import java.io.IOException;
import com.inteligr8.maven.aps.modeling.crawler.ApsFileTransformer;
/**
* This interface defines an APS file normalizer.
*
* Normalization is the transformation of something from one state to a target
* (normalized) state. In this context, a configuration is being normalized to
* be diff-friendly. That principally means the removal of dates. In theory,
* two normalized files will always match unless something of real substance
* has changed.
*/
public interface ApsFileNormalizer extends ApsFileTransformer {
}

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.normalizer;
import java.io.File;
@ -6,6 +20,13 @@ import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class implements an APS Form JSON configuration file normalizer.
*
* This does nothing but log at this time.
*
* @author brian@inteligr8.com
*/
public class ApsFormJsonNormalizer implements ApsFileNormalizer {
private final Logger logger = LoggerFactory.getLogger(ApsFormJsonNormalizer.class);

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.normalizer;
import java.io.File;
@ -14,6 +28,14 @@ import org.xml.sax.SAXException;
import com.inteligr8.maven.aps.modeling.util.ModelUtil;
/**
* This class implements an APS Process BPMN/XML configuration file normalizer.
*
* This will remove the 'exportDateTime' and 'modelLastUpdated' dates and
* 'modelVersion' of the process model.
*
* @author brian@inteligr8.com
*/
public class ApsProcessBpmnNormalizer implements ApsFileNormalizer {
private static final String NAMESPACE_ACTIVITI_MODELER = "http://activiti.com/modeler";

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.normalizer;
import java.io.File;
@ -12,12 +26,30 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import com.inteligr8.maven.aps.modeling.util.ApsModelArrayNodeSorter;
import com.inteligr8.maven.aps.modeling.util.ModelUtil;
/**
* This class implements an APS Process JSON configuration file normalizer.
*
* This will do nothing unless sorting is enabled. With sorting, it will order
* the 'childShapes' by their respective 'resourceId' values.
*
* @author brian@inteligr8.com
*/
public class ApsProcessJsonNormalizer implements ApsFileNormalizer {
private final Logger logger = LoggerFactory.getLogger(ApsProcessJsonNormalizer.class);
private final boolean enableSorting;
/**
* This constructor initializes the default normalizer with or without
* sorting.
*
* The sorting feature is available for a better "diff" experience. If
* you intend to commit the APS App configurations to Git, you will want to
* enable sorting.
*
* @param enableSorting true to re-order JSON objects; false to keep as-is.
*/
public ApsProcessJsonNormalizer(boolean enableSorting) {
this.enableSorting = enableSorting;
}
@ -33,8 +65,10 @@ public class ApsProcessJsonNormalizer implements ApsFileNormalizer {
ObjectNode jsonDescriptor = ModelUtil.getInstance().readJson(file, ObjectNode.class);
ArrayNode jsonChildShapes = this.getChildShapes(jsonDescriptor);
this.logger.trace("Found Process shapes: {}: {}", modelName, jsonChildShapes.size());
changed = ApsModelArrayNodeSorter.getInstance().sort(jsonChildShapes, "resourceId") || changed;
changed = ArrayNodeObjectSorter.getInstance().sort(jsonChildShapes, "resourceId") || changed;
this.logger.trace("Sorted Process shapes: {}: {}", modelName, changed);
if (changed)
ModelUtil.getInstance().writeJson(jsonDescriptor, file, this.enableSorting);

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.translator;
import java.io.File;
@ -15,6 +29,19 @@ import com.inteligr8.alfresco.activiti.model.GroupLight;
import com.inteligr8.maven.aps.modeling.util.Index;
import com.inteligr8.maven.aps.modeling.util.ModelUtil;
/**
* This class implements an APS App JSON configuration file translator.
*
* This will translate the IDs of all the APS App, Processes, and Organizations
* referenced in the APS App descriptor.
*
* Caution: in lieu of implementing APS User translation, APS User identity
* references are simply removed. Using APS Users in your APS models is bad
* practice. Use APS Organizations, even if that user is the only member of
* the group.
*
* @author brian@inteligr8.com
*/
public class ApsAppJsonTranslator extends ApsOrganizationHandler implements ApsFileTranslator {
private final Logger logger = LoggerFactory.getLogger(ApsAppJsonTranslator.class);
@ -22,35 +49,45 @@ public class ApsAppJsonTranslator extends ApsOrganizationHandler implements ApsF
private final Index<Long, String> apsProcessIndex;
private final Index<Long, String> fileProcessIndex;
/**
* This constructor initializes the default translator.
*
* @param api An APS API reference.
* @param apsProcessIndex A map of process IDs to process names as defined in the APS Service.
* @param apsOrgIndex A map of organizations (groups) to organization meta-data as defined in the APS Service.
* @param fileProcessIndex A map of process IDs to process names as used in the local process files.
*/
public ApsAppJsonTranslator(
ApsPublicRestApi api,
Map<String, GroupLight> apsOrgIndex,
Index<Long, String> apsProcessIndex,
Map<String, GroupLight> apsOrgIndex,
Index<Long, String> fileProcessIndex) {
super(api, apsOrgIndex);
this.apsOrgIndex = apsOrgIndex;
this.apsProcessIndex = apsProcessIndex;
this.apsOrgIndex = apsOrgIndex;
this.fileProcessIndex = fileProcessIndex;
}
@Override
public void translateFile(File file, String modelName, Long modelId) throws IOException {
public void translateFile(File file, String appName, Long appId) throws IOException {
this.logger.debug("Translating JSON file: {}", file);
boolean changed = false;
JsonNode descriptor = ModelUtil.getInstance().readJson(file);
JsonNode jsonDescriptor = ModelUtil.getInstance().readJson(file);
changed = this.translateModels(descriptor) || changed;
changed = this.translateIdentities(descriptor) || changed;
changed = this.translateModels(jsonDescriptor, appName) || changed;
changed = this.translateIdentities(jsonDescriptor, appName) || changed;
if (changed)
ModelUtil.getInstance().writeJson(descriptor, file, false);
ModelUtil.getInstance().writeJson(jsonDescriptor, file, false);
}
private boolean translateModels(JsonNode descriptor) {
private boolean translateModels(JsonNode jsonDescriptor, String appName) {
this.logger.trace("Translating processes in App: {}", appName);
boolean changed = false;
for (JsonNode _jsonModel : descriptor.get("definition").get("models")) {
for (JsonNode _jsonModel : jsonDescriptor.get("definition").get("models")) {
ObjectNode jsonModel = (ObjectNode)_jsonModel;
String fileProcessName = jsonModel.get("name").asText();
@ -91,10 +128,11 @@ public class ApsAppJsonTranslator extends ApsOrganizationHandler implements ApsF
return changed;
}
private boolean translateIdentities(JsonNode descriptor) {
private boolean translateIdentities(JsonNode jsonDescriptor, String appName) {
this.logger.trace("Translating identities in App: {}", appName);
boolean changed = false;
Iterator<JsonNode> i = descriptor.get("definition").get("publishIdentityInfo").iterator();
Iterator<JsonNode> i = jsonDescriptor.get("definition").get("publishIdentityInfo").iterator();
while (i.hasNext()) {
JsonNode jsonIdentityInfo = i.next();

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.translator;
import java.io.File;
@ -13,7 +27,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.inteligr8.alfresco.activiti.ApsPublicRestApi;
import com.inteligr8.alfresco.activiti.ApsPublicRestApiJerseyImpl;
import com.inteligr8.alfresco.activiti.api.ModelsApi.ModelType;
import com.inteligr8.alfresco.activiti.model.Datum;
import com.inteligr8.alfresco.activiti.model.GroupLight;
@ -23,6 +36,24 @@ import com.inteligr8.maven.aps.modeling.crawler.ApsAppCrawlable;
import com.inteligr8.maven.aps.modeling.crawler.ApsFileTransformer;
import com.inteligr8.maven.aps.modeling.util.Index;
/**
* This class defines an APS App package translator.
*
* An APS App package is a ZIP file that contains multiple files in a
* predictable folder hierachy with predictable file names. It is effectively
* an APS App interchange format specification.
*
* A package must have at least a single configuration file at the root of the
* ZIP package in the JSON format. It must be named the APS App name. That
* file will then reference all the model elements contained in the ZIP. Any
* model elements not referenced will simply be ignored by APS and by this
* plugin.
*
* This class has methods that provide translator for all the various model
* elements in an APS App package.
*
* @author brian@inteligr8.com
*/
public class ApsAppTranslator implements ApsAppCrawlable {
private final Logger logger = LoggerFactory.getLogger(ApsAppTranslator.class);
@ -38,11 +69,27 @@ public class ApsAppTranslator implements ApsAppCrawlable {
private Index<Long, String> fileProcessIndex;
private Index<Long, String> fileSubprocessIndex;
public ApsAppTranslator(File apsAppDirectory, ApsPublicRestApiJerseyImpl api) {
/**
* This constructor initializes the default translator.
*
* The specified directory and a reference to the APS Service are both
* required. This way the configuration file can be cross-referenced with
* the APS App IDs on the target APS instance.
*
* @param apsAppDirectory The directory of the unpacked APS package.
* @param api An APS API reference.
*/
public ApsAppTranslator(File apsAppDirectory, ApsPublicRestApi api) {
this.api = api;
this.appDirectory = apsAppDirectory;
}
/**
* This method initializes the data required from the APS Service for the
* function of this class.
*
* @throws IOException A network I/O related issue occurred.
*/
public synchronized void buildIndexes() throws IOException {
if (this.indexesBuilt)
return;
@ -96,8 +143,8 @@ public class ApsAppTranslator implements ApsAppCrawlable {
return new ApsAppJsonTranslator(
this.api,
this.apsOrgIndex,
this.apsProcessIndex,
this.apsOrgIndex,
this.fileProcessIndex);
}

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.translator;
import java.io.File;
@ -5,6 +19,14 @@ import java.io.IOException;
import com.inteligr8.maven.aps.modeling.crawler.ApsFileTransformer;
/**
* This interface defines an APS file translator.
*
* Translation is the transformation of something from one state to a target
* state. In this context, a configuration is being translated to be import
* friendly for the target APS Service. That principally means the update
* of APS model IDs.
*/
public interface ApsFileTranslator extends ApsFileTransformer {
@Override
@ -12,6 +34,15 @@ public interface ApsFileTranslator extends ApsFileTransformer {
this.translateFile(file, modelName, modelId);
}
/**
* This method translates the specified file which should be referred to
* with the specified name and ID.
*
* @param file A model file.
* @param modelName The target model name.
* @param modelId The target model ID.
* @throws IOException An I/O related exception has occurred during translation.
*/
void translateFile(File file, String modelName, Long modelId) throws IOException;
}

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.translator;
import java.io.File;
@ -11,11 +25,23 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import com.inteligr8.maven.aps.modeling.util.Index;
import com.inteligr8.maven.aps.modeling.util.ModelUtil;
/**
* This class implements an APS Form JSON configuration file translator.
*
* This will translate the form ID embedded into APS Form descriptor.
*
* @author brian@inteligr8.com
*/
public class ApsFormJsonTranslator implements ApsFileTranslator {
private final Logger logger = LoggerFactory.getLogger(ApsFormJsonTranslator.class);
private final Index<Long, String> apsIndex;
/**
* This constructor initializes the default translator.
*
* @param apsFormIndex A map of form IDs to form names as defined in the APS Service.
*/
public ApsFormJsonTranslator(Index<Long, String> apsFormIndex) {
this.apsIndex = apsFormIndex;
}

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.translator;
import java.util.Map;
@ -9,12 +23,21 @@ import com.inteligr8.alfresco.activiti.ApsPublicRestApi;
import com.inteligr8.alfresco.activiti.model.Group;
import com.inteligr8.alfresco.activiti.model.GroupLight;
/**
* This class provides APS Organization support.
*
* @author brian@inteligr8.com.
*/
public class ApsOrganizationHandler {
private final Logger logger = LoggerFactory.getLogger(ApsOrganizationHandler.class);
private final ApsPublicRestApi api;
private final Map<String, GroupLight> apsOrgIndex;
/**
* @param api An APS API reference.
* @param apsOrgIndex A map of organization IDs to organization meta-data defined in the APS service.
*/
public ApsOrganizationHandler(
ApsPublicRestApi api,
Map<String, GroupLight> apsOrgIndex) {

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.translator;
import java.io.File;
@ -27,6 +41,19 @@ import com.inteligr8.alfresco.activiti.model.GroupLight;
import com.inteligr8.maven.aps.modeling.util.Index;
import com.inteligr8.maven.aps.modeling.util.ModelUtil;
/**
* This class implements an APS Process BPMN/XML configuration file translator.
*
* This will translate the IDs of all the APS Process, Organizations, and
* Forms referenced in the APS Process BPMN.
*
* Caution: in lieu of implementing APS User translation, APS User identity
* references are simply removed. Using APS Users in your APS models is bad
* practice. Use APS Organizations, even if that user is the only member of
* the group.
*
* @author brian@inteligr8.com
*/
public class ApsProcessBpmnTranslator extends ApsOrganizationHandler implements ApsFileTranslator {
private static final String NAMESPACE_ACTIVITI = "http://activiti.org/bpmn";
@ -38,6 +65,15 @@ public class ApsProcessBpmnTranslator extends ApsOrganizationHandler implements
private final Index<Long, String> apsFormIndex;
private final Index<Long, String> fileFormIndex;
/**
* This constructor initializes the default translator.
*
* @param api An APS API reference.
* @param apsProcessIndex A map of process IDs to process names as defined in the APS Service.
* @param apsOrgIndex A map of organizations (groups) to organization meta-data as defined in the APS Service.
* @param apsFormIndex A map of form IDs to form names as defined in the APS Service.
* @param fileFormIndex A map of form IDS to form names as used in the local form files.
*/
public ApsProcessBpmnTranslator(
ApsPublicRestApi api,
Index<Long, String> apsProcessIndex,

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.translator;
import java.io.File;
@ -15,6 +29,19 @@ import com.inteligr8.alfresco.activiti.model.GroupLight;
import com.inteligr8.maven.aps.modeling.util.Index;
import com.inteligr8.maven.aps.modeling.util.ModelUtil;
/**
* This class implements an APS Process JSON configuration file translator.
*
* This will translate the IDs of all the APS Process, Organizations, and
* Forms referenced in the APS Process descriptor.
*
* Caution: in lieu of implementing APS User translation, APS User identity
* references are simply removed. Using APS Users in your APS models is bad
* practice. Use APS Organizations, even if that user is the only member of
* the group.
*
* @author brian@inteligr8.com
*/
public class ApsProcessJsonTranslator extends ApsOrganizationHandler implements ApsFileTranslator {
private final Logger logger = LoggerFactory.getLogger(ApsProcessJsonTranslator.class);
@ -22,6 +49,14 @@ public class ApsProcessJsonTranslator extends ApsOrganizationHandler implements
private final Map<String, GroupLight> apsOrgIndex;
private final Index<Long, String> apsFormIndex;
/**
* This constructor initializes the default translator.
*
* @param api An APS API reference.
* @param apsProcessIndex A map of process IDs to process names as defined in the APS Service.
* @param apsOrgIndex A map of organizations (groups) to organization meta-data as defined in the APS Service.
* @param apsFormIndex A map of form IDs to form names as defined in the APS Service.
*/
public ApsProcessJsonTranslator(
ApsPublicRestApi api,
Index<Long, String> apsProcessIndex,
@ -42,21 +77,22 @@ public class ApsProcessJsonTranslator extends ApsOrganizationHandler implements
ObjectNode jsonDescriptor = ModelUtil.getInstance().readJson(file, ObjectNode.class);
changed = this.translateResourceId(jsonDescriptor, apsProcessId) || changed;
changed = this.translateOrganizations(jsonDescriptor) || changed;
changed = this.translateForms(jsonDescriptor) || changed;
changed = this.translateSubprocesses(jsonDescriptor) || changed;
changed = this.translateResourceId(jsonDescriptor, processName, apsProcessId) || changed;
changed = this.translateOrganizations(jsonDescriptor, processName) || changed;
changed = this.translateForms(jsonDescriptor, processName) || changed;
changed = this.translateSubprocesses(jsonDescriptor, processName) || changed;
if (changed)
ModelUtil.getInstance().writeJson(jsonDescriptor, file, false);
}
private boolean translateResourceId(ObjectNode jsonDescriptor, Long apsProcessId) {
private boolean translateResourceId(ObjectNode jsonDescriptor, String processName, Long apsProcessId) {
if (apsProcessId == null) {
this.logger.trace("The process is not in APS; treating as new");
return false;
}
this.logger.trace("Translating resource ID in process: {}", processName);
ObjectNode resourceIdParentJson = jsonDescriptor;
JsonNode jsonResourceId = jsonDescriptor.get("resourceId");
@ -83,7 +119,8 @@ public class ApsProcessJsonTranslator extends ApsOrganizationHandler implements
private boolean translateOrganizations(ObjectNode jsonDescriptor) {
private boolean translateOrganizations(ObjectNode jsonDescriptor, String processName) {
this.logger.trace("Translating organizations in process: {}", processName);
boolean changed = false;
for (JsonNode jsonChildShape : this.getChildShapes(jsonDescriptor)) {
@ -134,7 +171,8 @@ public class ApsProcessJsonTranslator extends ApsOrganizationHandler implements
private boolean translateForms(ObjectNode jsonDescriptor) {
private boolean translateForms(ObjectNode jsonDescriptor, String processName) {
this.logger.trace("Translating forms in process: {}", processName);
boolean changed = false;
for (JsonNode jsonChildShape : this.getChildShapes(jsonDescriptor)) {
@ -168,7 +206,8 @@ public class ApsProcessJsonTranslator extends ApsOrganizationHandler implements
private boolean translateSubprocesses(ObjectNode jsonDescriptor) {
private boolean translateSubprocesses(ObjectNode jsonDescriptor, String processName) {
this.logger.trace("Translating subprocesses in process: {}", processName);
boolean changed = false;
for (JsonNode jsonChildShape : this.getChildShapes(jsonDescriptor)) {

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.util;
import java.util.HashMap;
@ -9,55 +23,114 @@ import java.util.Set;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* A class that implements bi-directional map for forward and reverse indexing
* and lookups.
*
* The index is considered to be many-to-1. So the forward index appears as
* 1-to-1 (one key to one value) and the reverse index appears as 1-to-many
* (one value to many keys).
*
* If the index should be considered to be 1-to-1, then set
* `allowDuplicateValues` to `false`.
*
* @author brian@inteligr8.com
*/
public class Index<K, V> {
private final Map<K, V> forwardMap;
private final Map<V, Set<K>> reverseMap;
private final boolean allowDuplicateValues;
/**
* This constructor defines a new index with some meta-data.
*
* The capacity is not strictly enforced. It should be accurate for
* performance reasons.
*
* @param initialCapacity A capacity, as you would specify in an ArrayList or HashMap.
* @param allowDuplicateValues true to allow multiple keys to have the same value; false to throw an IllegalArgumentException.
*/
public Index(int initialCapacity, boolean allowDuplicateValues) {
this.forwardMap = new HashMap<K, V>(initialCapacity);
this.reverseMap = new HashMap<V, Set<K>>(initialCapacity);
this.allowDuplicateValues = allowDuplicateValues;
}
/**
* @param key An index key.
* @return true if it exists; false otherwise.
*/
public boolean containsKey(K key) {
return this.forwardMap.containsKey(key);
}
/**
* @param value An indexed value.
* @return true if it exists; false otherwise.
*/
public boolean containsValue(V value) {
return this.reverseMap.containsKey(value);
}
/**
* @param key An index key.
* @return The value; null if key not indexed.
*/
public V getValue(K key) {
return this.forwardMap.get(key);
}
/**
* @return A set of all keys; may be empty; never null.
*/
public Set<K> keySet() {
return this.forwardMap.keySet();
}
/**
* @return A set of all values; may be empty; never null.
*/
public Set<V> valueSet() {
return this.reverseMap.keySet();
}
/**
* @param value An indexed value.
* @return A set of keys; never empty; null if value not indexed.
*/
public Set<K> getKeys(V value) {
return this.reverseMap.get(value);
}
/**
* @param value An indexed value.
* @return The key; null if value not indexed.
*/
public K getFirstKey(V value) {
Set<K> keys = this.reverseMap.get(value);
return (keys == null || keys.isEmpty()) ? null : keys.iterator().next();
}
/**
* @return The number of keys in the index.
*/
public int size() {
return this.forwardMap.size();
}
/**
* @return Interable access to the entries of the forward index.
*/
public Iterable<Entry<K, V>> entries() {
return this.forwardMap.entrySet();
}
/**
* @param key An index key.
* @param value A value to index to the specified key.
* @return true if the key already existed and was overwritten; false otherwise.
*/
public synchronized boolean put(K key, V value) {
boolean overwrote = false;
@ -81,6 +154,10 @@ public class Index<K, V> {
return overwrote;
}
/**
* @param key An index key.
* @return true if the key and its value were removed; false otherwise.
*/
public synchronized boolean remove(K key) {
V oldValue = this.forwardMap.remove(key);
if (oldValue == null)
@ -91,6 +168,9 @@ public class Index<K, V> {
return true;
}
/**
* This method clears/resets the index.
*/
public synchronized void clear() {
this.forwardMap.clear();
this.reverseMap.clear();

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.util;
import java.util.Arrays;
@ -5,15 +19,41 @@ import java.util.Comparator;
import java.util.List;
import java.util.Map;
/**
* This class implements a comparator for the value of map keys.
*
* If key values are considered equal, fallback keys are supported. Any map
* without the key or not null value will be considered "greater than" ones
* that have values for the specified key. This will move them to the end of
* any sorted list.
*
* @author brian@inteligr8.com
*/
public class MapComparator<K, V> implements Comparator<Map<K, V>> {
//private final Logger logger = LoggerFactory.getLogger(ArrayOfObjectNodeComparator.class);
private final List<K> keys;
/**
* An array-based constructor.
*
* The class will sort on the values of these map keys, with a priority in
* the specified order.
*
* @param keys An array of keys.
*/
public MapComparator(@SuppressWarnings("unchecked") K... keys) {
this(Arrays.asList(keys));
}
/**
* A list-based constructor.
*
* The class will sort on the values of these map keys, with a priority in
* the specified order.
*
* @param keys A list of keys.
*/
public MapComparator(List<K> keys) {
this.keys = keys;
}

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.util;
import java.io.BufferedInputStream;
@ -40,11 +54,19 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.inteligr8.maven.aps.modeling.xml.DomNamespaceContext;
/**
* This singleton class provides JSON and XML I/O tools and consistent formatting.
*
* @author brian@inteligr8.com
*/
public class ModelUtil {
public final static QName CDATA_FLEX = QName.valueOf("inteligr8:xml:cdata_or_element");
private final static ModelUtil INSTANCE = new ModelUtil();
/**
* @return A singleton instance of this class.
*/
public static ModelUtil getInstance() {
return INSTANCE;
}
@ -89,11 +111,42 @@ public class ModelUtil {
/**
* This method reads/parses JSON and immediately formats/writes JSON back
* to the specified file.
*
* You many optionally enable the sorting of elements. Sorting makes the
* files more diff-friendly. The algorithm will sort JSON objects by keys.
* JSON array values will not be sorted.
*
* This method will load the full set of JSON objects into memory.
*
* @param inplaceFile A file handle to an existing valid JSON file.
* @param enableSorting true to sort; false to leave as-is.
* @throws IOException A file I/O issue occurred.
*/
public void json(File inplaceFile, boolean enableSorting) throws IOException {
JsonNode json = this.readJson(inplaceFile);
this.writeJson(json, inplaceFile, enableSorting);
}
/**
* This method reads/parses JSON from the specified source file and
* immediately formats/writes JSON to the specified target file.
*
* If the specified target file already exists, it will be overwritten.
*
* You many optionally enable the sorting of elements. Sorting makes the
* files more diff-friendly. The algorithm will sort JSON objects by keys.
* JSON array values will not be sorted.
*
* This method will load the full set of JSON objects into memory.
*
* @param sourceFile A file handle to an existing valid JSON file.
* @param targetFile A file handle for the target JSON file.
* @param enableSorting true to sort; false to leave as-is.
* @throws IOException A file I/O issue occurred.
*/
public void json(File sourceFile, File targetFile, boolean enableSorting) throws IOException {
FileInputStream fistream = new FileInputStream(sourceFile);
BufferedInputStream bistream = new BufferedInputStream(fistream, this.bufferSize);
@ -110,16 +163,45 @@ public class ModelUtil {
}
}
/**
* This method reads/parses JSON from the specified source stream and
* immediately formats/writes JSON to the specified target stream.
*
* You many optionally enable the sorting of elements. Sorting makes the
* files more diff-friendly. The algorithm will sort JSON objects by keys.
* JSON array values will not be sorted.
*
* This method will load the full set of JSON objects into memory.
*
* @param istream An input stream to valid JSON.
* @param ostream An output stream.
* @param enableSorting true to sort; false to leave as-is.
* @throws IOException A stream I/O issue occurred.
*/
public void json(InputStream istream, OutputStream ostream, boolean enableSorting) throws IOException {
// FIXME stream it for lower memory/IO usage
JsonNode json = this.readJson(istream);
this.writeJson(json, ostream, enableSorting);
}
/**
* This method reads/parses JSON from the specified file.
*
* @param file A file handle to an existing valid JSON file.
* @return A JSON node (array, object, or value).
* @throws IOException A file I/O issue occurred.
*/
public JsonNode readJson(File file) throws IOException {
return this.readJson(file, JsonNode.class);
}
/**
* This method reads/parses JSON from the specified file.
*
* @param file A file handle to an existing valid JSON file.
* @param type A type parse the JSON into (using the Jackson parser).
* @return An instance of the specified type.
* @throws IOException A file I/O issue occurred.
*/
public <T> T readJson(File file, Class<T> type) throws IOException {
FileInputStream fistream = new FileInputStream(file);
BufferedInputStream bistream = new BufferedInputStream(fistream, this.bufferSize);
@ -130,6 +212,13 @@ public class ModelUtil {
}
}
/**
* This method reads/parses JSON from the specified file.
*
* @param file A file handle to an existing valid JSON file.
* @return A JSON array as a list.
* @throws IOException A file I/O issue occurred.
*/
public <T> List<T> readJsonAsList(File file) throws IOException {
FileInputStream fistream = new FileInputStream(file);
BufferedInputStream bistream = new BufferedInputStream(fistream, this.bufferSize);
@ -140,6 +229,13 @@ public class ModelUtil {
}
}
/**
* This method reads/parses JSON from the specified file.
*
* @param file A file handle to an existing valid JSON file.
* @return A JSON object as a map.
* @throws IOException A file I/O issue occurred.
*/
public Map<String, Object> readJsonAsMap(File file) throws IOException {
FileInputStream fistream = new FileInputStream(file);
BufferedInputStream bistream = new BufferedInputStream(fistream, this.bufferSize);
@ -150,24 +246,67 @@ public class ModelUtil {
}
}
/**
* This method reads/parses JSON from the specified stream.
*
* @param istream An input stream to valid JSON.
* @return A JSON node (array, object, or value).
* @throws IOException A stream I/O issue occurred.
*/
public JsonNode readJson(InputStream istream) throws IOException {
return this.om.readTree(istream);
}
/**
* This method reads/parses JSON from the specified stream.
*
* @param istream An input stream to valid JSON.
* @param type A type parse the JSON into (using the Jackson parser).
* @return An instance of the specified type.
* @throws IOException A stream I/O issue occurred.
*/
public <T> T readJson(InputStream istream, Class<T> type) throws IOException {
return this.om.readValue(istream, type);
}
/**
* This method reads/parses JSON from the specified stream.
*
* @param istream An input stream to valid JSON.
* @return A JSON array as a list.
* @throws IOException A stream I/O issue occurred.
*/
@SuppressWarnings("unchecked")
public <T> List<T> readJsonAsList(InputStream istream) throws IOException {
return this.om.readValue(istream, List.class);
}
/**
* This method reads/parses JSON from the specified stream.
*
* @param istream An input stream to valid JSON.
* @return A JSON object as a map.
* @throws IOException A stream I/O issue occurred.
*/
@SuppressWarnings("unchecked")
public Map<String, Object> readJsonAsMap(InputStream istream) throws IOException {
return this.om.readValue(istream, Map.class);
}
/**
* This method formats/writes JSON to the specified file.
*
* If the specified file already exists, it will be overwritten.
*
* You many optionally enable the sorting of elements. Sorting makes the
* files more diff-friendly. The algorithm will sort JSON objects by keys.
* JSON array values will not be sorted.
*
* @param json A JSON node (array, object, or value).
* @param file A file handle.
* @param enableSorting true to sort; false to leave as-is.
* @throws IOException A file I/O issue occurred.
*/
public void writeJson(JsonNode json, File file, boolean enableSorting) throws IOException {
FileOutputStream fostream = new FileOutputStream(file);
BufferedOutputStream bostream = new BufferedOutputStream(fostream, this.bufferSize);
@ -178,6 +317,20 @@ public class ModelUtil {
}
}
/**
* This method formats/writes JSON to the specified file.
*
* If the specified file already exists, it will be overwritten.
*
* You many optionally enable the sorting of elements. Sorting makes the
* files more diff-friendly. The algorithm will sort JSON objects by keys.
* JSON array values will not be sorted.
*
* @param map A Java map.
* @param file A file handle.
* @param enableSorting true to sort; false to leave as-is.
* @throws IOException A file I/O issue occurred.
*/
public void writeJson(Map<String, Object> map, File file, boolean enableSorting) throws IOException {
FileOutputStream fostream = new FileOutputStream(file);
BufferedOutputStream bostream = new BufferedOutputStream(fostream, this.bufferSize);
@ -188,6 +341,18 @@ public class ModelUtil {
}
}
/**
* This method formats/writes JSON to the specified file.
*
* You many optionally enable the sorting of elements. Sorting makes the
* files more diff-friendly. The algorithm will sort JSON objects by keys.
* JSON array values will not be sorted.
*
* @param json A JSON node (array, object, or value).
* @param ostream An output stream.
* @param enableSorting true to sort; false to leave as-is.
* @throws IOException A file I/O issue occurred.
*/
public void writeJson(JsonNode json, OutputStream ostream, boolean enableSorting) throws IOException {
if (enableSorting) {
this.omsorted.writeValue(ostream, json);
@ -196,6 +361,18 @@ public class ModelUtil {
}
}
/**
* This method formats/writes JSON to the specified file.
*
* You many optionally enable the sorting of elements. Sorting makes the
* files more diff-friendly. The algorithm will sort JSON objects by keys.
* JSON array values will not be sorted.
*
* @param map A Java map.
* @param ostream An output stream.
* @param enableSorting true to sort; false to leave as-is.
* @throws IOException A file I/O issue occurred.
*/
public void writeJson(Map<String, Object> map, OutputStream ostream, boolean enableSorting) throws IOException {
if (enableSorting) {
this.omsorted.writeValue(ostream, map);
@ -206,6 +383,17 @@ public class ModelUtil {
/**
* This method reads/parses XML and immediately formats/writes XML back to
* the specified file.
*
* This method will load the full DOM of XML into memory.
*
* @param inplaceFile A file handle to an existing valid XML file.
* @throws IOException A file I/O issue occurred.
* @throws SAXException The file is not valid XML.
* @throws TransformerException An unknown XML transformation issue occurred.
*/
public void xml(File inplaceFile) throws IOException, SAXException, TransformerException {
Document xml;
@ -226,6 +414,20 @@ public class ModelUtil {
}
}
/**
* This method reads/parses XML from the specified source file and
* immediately formats/writes XML to to the specified target file.
*
* If the specified target file already exists, it will be overwritten.
*
* This method will load the full DOM of XML into memory.
*
* @param sourceFile A file handle to an existing valid XML file.
* @param targetFile A file handle.
* @throws IOException A file I/O issue occurred.
* @throws SAXException The file is not valid XML.
* @throws TransformerException An unknown XML transformation issue occurred.
*/
public void xml(File sourceFile, File targetFile) throws IOException, SAXException, TransformerException {
FileInputStream fistream = new FileInputStream(sourceFile);
BufferedInputStream bistream = new BufferedInputStream(fistream, this.bufferSize);
@ -242,12 +444,31 @@ public class ModelUtil {
}
}
/**
* This method reads/parses XML from the specified source stream and
* immediately formats/writes XML to to the specified target stream.
*
* This method will load the full DOM of XML into memory.
*
* @param sourceFile A file handle to an existing valid XML file.
* @param targetFile A file handle.
* @throws IOException A file I/O issue occurred.
* @throws SAXException The file is not valid XML.
* @throws TransformerException An unknown XML transformation issue occurred.
*/
public void xml(InputStream istream, OutputStream ostream) throws IOException, SAXException, TransformerException {
// FIXME stream it for lower memory/IO usage
Document doc = this.readXml(istream);
this.writeXml(doc, ostream);
}
/**
* This method reads/parses XML from the specified file.
*
* @param file A file handle to an existing valid XML file.
* @return An XML DOM Document object.
* @throws IOException A file I/O issue occurred.
* @throws SAXException The file is not valid XML.
*/
public Document readXml(File file) throws IOException, SAXException {
FileInputStream fistream = new FileInputStream(file);
BufferedInputStream bistream = new BufferedInputStream(fistream, this.bufferSize);
@ -258,10 +479,28 @@ public class ModelUtil {
}
}
/**
* This method reads/parses XML from the specified stream.
*
* @param istream An input stream to valid XML.
* @return An XML DOM Document object.
* @throws IOException A stream I/O issue occurred.
* @throws SAXException The stream is not valid XML.
*/
public Document readXml(InputStream istream) throws IOException, SAXException {
return this.docBuilder.parse(istream);
}
/**
* This method formats/writes XML to the specified file.
*
* If the specified file already exists, it will be overwritten.
*
* @param xml An XML element.
* @param file A file handle.
* @throws IOException A file I/O issue occurred.
* @throws TransformerException An unknown XML transformation issue occurred.
*/
public void writeXml(Node xml, File file) throws IOException, TransformerException {
FileOutputStream fostream = new FileOutputStream(file);
BufferedOutputStream bostream = new BufferedOutputStream(fostream, this.bufferSize);
@ -272,16 +511,43 @@ public class ModelUtil {
}
}
/**
* This method formats/writes XML to the specified stream.
*
* @param xml An XML element.
* @param ostream An output stream.
* @throws IOException A stream I/O issue occurred.
* @throws TransformerException An unknown XML transformation issue occurred.
*/
public void writeXml(Node xml, OutputStream ostream) throws IOException, TransformerException {
DOMSource source = new DOMSource(xml);
StreamResult result = new StreamResult(ostream);
this.transformer.transform(source, result);
}
/**
* This method searches the DOM using an XPath expression.
*
* @param node An XML node.
* @param xpathExpr An XPath expression.
* @return An XML DOM list of nodes object; null if no result.
* @throws XPathExpressionException An unknown XPath issue occurred.
*/
public NodeList xpath(Node node, String xpathExpr) throws XPathExpressionException {
return (NodeList)this.xpath(node, xpathExpr, XPathConstants.NODESET);
}
/**
* This method searches the DOM using an XPath expression.
*
* @param node An XML node.
* @param xpathExpr An XPath expression.
* @param returnType An XPath return type: see XPathConstants.
* @return An XML DOM list of nodes object; null if no result.
* @throws XPathExpressionException An unknown XPath issue occurred.
*/
public Object xpath(Node node, String xpathExpr, QName returnType) throws XPathExpressionException {
XPath xpath = this.xpathfactory.newXPath();
xpath.setNamespaceContext(new DomNamespaceContext(node));

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.util;
import java.util.Arrays;
@ -6,15 +20,45 @@ import java.util.List;
import com.fasterxml.jackson.databind.JsonNode;
/**
* This class implements a comparator for the value of JSON object fields.
*
* If field values are considered equal, fallback fields are supported. Any
* object without the field in question will be considered "greater than" ones
* that have the specified field. This will move them to the end of any sorted
* list.
*
* If a JSON value or array is encountered instead of a JSON object, then it is
* treated exactly like a JSON object without the specified field. It will be
* considered "greater than" and move to the end of any sorted list.
*
* @author brian@inteligr8.com
*/
public class ObjectNodeComparator implements Comparator<JsonNode> {
//private final Logger logger = LoggerFactory.getLogger(ArrayOfObjectNodeComparator.class);
private final List<String> objectFieldNames;
/**
* An array-based constructor.
*
* The class will sort on the values of these JSON object field names, with
* a priority in the specified order.
*
* @param objectFieldNames An array of JSON object field names.
*/
public ObjectNodeComparator(String... objectFieldNames) {
this(Arrays.asList(objectFieldNames));
}
/**
* A list-based constructor.
*
* The class will sort on the values of these JSON object field names, with
* a priority in the specified order.
*
* @param objectFieldNames A list of JSON object field names.
*/
public ObjectNodeComparator(List<String> objectFieldNames) {
this.objectFieldNames = objectFieldNames;
}
@ -22,9 +66,9 @@ public class ObjectNodeComparator implements Comparator<JsonNode> {
@Override
public int compare(JsonNode o1, JsonNode o2) {
if (!o1.isObject())
return -1;
if (!o2.isObject())
return 1;
if (!o2.isObject())
return -1;
for (String objectFieldName : objectFieldNames) {
JsonNode value1 = o1.get(objectFieldName);

View File

@ -1,3 +1,17 @@
/*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.inteligr8.maven.aps.modeling.xml;
import java.util.Collections;
@ -9,6 +23,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
/**
* This class implements namespace handling for DOM processing.
*/
public class DomNamespaceContext implements NamespaceContext {
private final Logger logger = LoggerFactory.getLogger(DomNamespaceContext.class);
@ -16,10 +33,22 @@ public class DomNamespaceContext implements NamespaceContext {
private final String defaultNamespacePrefix;
private final String defaultNamespace;
/**
* The constructor using just a DOM node. The default namespace prefix is
* assumed to be 'tns'.
*
* @param node A DOM node.
*/
public DomNamespaceContext(Node node) {
this(node, "tns");
}
/**
* The constructor using just a DOM node.
*
* @param node A DOM node.
* @param defaultNamespacePrefix A DOM namespace prefix.
*/
public DomNamespaceContext(Node node, String defaultNamespacePrefix) {
this.node = node;
this.defaultNamespacePrefix = defaultNamespacePrefix;