initial checkin
This commit is contained in:
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# Maven
|
||||
target
|
||||
pom.xml.versionsBackup
|
||||
|
||||
# Eclipse
|
||||
.project
|
||||
.classpath
|
||||
.settings
|
||||
.vscode
|
||||
|
||||
# IDEA
|
||||
/.idea/
|
1
asie-api/.gitignore
vendored
Normal file
1
asie-api/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target/
|
70
asie-api/pom.xml
Normal file
70
asie-api/pom.xml
Normal file
@@ -0,0 +1,70 @@
|
||||
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.inteligr8.alfresco</groupId>
|
||||
<artifactId>asie-api</artifactId>
|
||||
<version>1.0-SNAPSHOT-asie2</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ASIE JAX-RS API</name>
|
||||
<description>Alfresco Search & Insight Engine JAX-RS API</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.inteligr8</groupId>
|
||||
<artifactId>solr-api</artifactId>
|
||||
<version>1.0-SNAPSHOT-solr6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-repository</artifactId>
|
||||
<version>14.153</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Including for testing purposes only -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>5.11.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<maven.compiler.release>11</maven.compiler.release>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<!-- avoids log4j dependency -->
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.13.0</version>
|
||||
</plugin>
|
||||
<!-- avoids struts dependency -->
|
||||
<plugin>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>3.12.1</version>
|
||||
</plugin>
|
||||
<!-- Force use of a new maven-dependency-plugin that doesn't download struts dependency -->
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>3.7.1</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>alfresco-public</id>
|
||||
<url>https://artifacts.alfresco.com/nexus/repository/public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
</project>
|
@@ -0,0 +1,91 @@
|
||||
package com.inteligr8.alfresco.asie.api;
|
||||
|
||||
import com.inteligr8.alfresco.asie.model.ActionResponse;
|
||||
import com.inteligr8.alfresco.asie.model.EmptyResponse;
|
||||
import com.inteligr8.alfresco.asie.model.core.CheckRequest;
|
||||
import com.inteligr8.alfresco.asie.model.core.DisableIndexingRequest;
|
||||
import com.inteligr8.alfresco.asie.model.core.EnableIndexingRequest;
|
||||
import com.inteligr8.alfresco.asie.model.core.FixRequest;
|
||||
import com.inteligr8.alfresco.asie.model.core.FixResponseAction;
|
||||
import com.inteligr8.alfresco.asie.model.core.IndexingStatusAction;
|
||||
import com.inteligr8.alfresco.asie.model.core.NewCoreRequest;
|
||||
import com.inteligr8.alfresco.asie.model.core.NewDefaultIndexRequest;
|
||||
import com.inteligr8.alfresco.asie.model.core.PurgeRequest;
|
||||
import com.inteligr8.alfresco.asie.model.core.ReindexRequest;
|
||||
import com.inteligr8.alfresco.asie.model.core.ReportRequest;
|
||||
import com.inteligr8.alfresco.asie.model.core.ReportResponse;
|
||||
import com.inteligr8.alfresco.asie.model.core.RetryRequest;
|
||||
import com.inteligr8.alfresco.asie.model.core.RetryResponseAction;
|
||||
import com.inteligr8.alfresco.asie.model.core.SummaryRequest;
|
||||
import com.inteligr8.alfresco.asie.model.core.SummaryResponse;
|
||||
import com.inteligr8.alfresco.asie.model.core.UpdateCoreRequest;
|
||||
import com.inteligr8.alfresco.asie.model.core.UpdateLog4jRequest;
|
||||
import com.inteligr8.alfresco.asie.model.core.UpdateSharedRequest;
|
||||
import com.inteligr8.solr.model.ResponseAction;
|
||||
|
||||
import jakarta.ws.rs.BeanParam;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
|
||||
@Path("admin/cores")
|
||||
public interface CoreAdminApi extends com.inteligr8.solr.api.CoreAdminApi {
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
EmptyResponse newCore(@BeanParam NewCoreRequest request);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
EmptyResponse newDefaultIndex(@BeanParam NewDefaultIndexRequest request);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
ActionResponse<ResponseAction> updateCore(@BeanParam UpdateCoreRequest request);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
ActionResponse<ResponseAction> check(@BeanParam CheckRequest request);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
ActionResponse<ResponseAction> updateShared(@BeanParam UpdateSharedRequest request);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
ActionResponse<ResponseAction> updateLog4j(@BeanParam UpdateLog4jRequest request);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
ActionResponse<ResponseAction> purge(@BeanParam PurgeRequest request);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
ActionResponse<ResponseAction> reindex(@BeanParam ReindexRequest request);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
ActionResponse<RetryResponseAction> retry(@BeanParam RetryRequest request);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
ActionResponse<FixResponseAction> fix(@BeanParam FixRequest request);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
ActionResponse<IndexingStatusAction> enableIndexing(@BeanParam EnableIndexingRequest request);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
ActionResponse<IndexingStatusAction> disableIndexing(@BeanParam DisableIndexingRequest request);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
ReportResponse getReport(@BeanParam ReportRequest request);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
SummaryResponse getSummary(@BeanParam SummaryRequest request);
|
||||
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
package com.inteligr8.alfresco.asie.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty.Access;
|
||||
import com.inteligr8.solr.model.ResponseAction;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ActionResponse<T extends ResponseAction> extends BaseResponse {
|
||||
|
||||
@JsonProperty(access = Access.READ_ONLY)
|
||||
private T action;
|
||||
|
||||
public T getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
protected void setAction(T action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
package com.inteligr8.alfresco.asie.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty.Access;
|
||||
|
||||
public class BaseResponse extends com.inteligr8.solr.model.BaseResponse {
|
||||
|
||||
@JsonProperty(value = "STATUS", access = Access.READ_ONLY)
|
||||
private String reason;
|
||||
|
||||
@JsonProperty(value = "exception", access = Access.READ_ONLY)
|
||||
private String exception;
|
||||
|
||||
@JsonProperty(value = "msg", access = Access.READ_ONLY)
|
||||
private String message;
|
||||
|
||||
public String getReason() {
|
||||
return reason;
|
||||
}
|
||||
|
||||
protected void setReason(String reason) {
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
public String getException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
protected void setException(String exception) {
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
protected void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
package com.inteligr8.alfresco.asie.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class EmptyResponse extends BaseResponse {
|
||||
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import com.inteligr8.solr.model.JsonFormattedResponseRequest;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
|
||||
public class CheckRequest extends JsonFormattedResponseRequest<CheckRequest> {
|
||||
|
||||
private static final String ACTION = "check";
|
||||
|
||||
@QueryParam("action")
|
||||
@DefaultValue(ACTION)
|
||||
@Nonnull
|
||||
private String action = ACTION;
|
||||
|
||||
@QueryParam("coreName")
|
||||
@Nonnull
|
||||
private String core;
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String getCore() {
|
||||
return core;
|
||||
}
|
||||
|
||||
public void setCore(String core) {
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
public CheckRequest withCore(String core) {
|
||||
this.core = core;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import com.inteligr8.solr.model.JsonFormattedResponseRequest;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
|
||||
public class DisableIndexingRequest extends JsonFormattedResponseRequest<DisableIndexingRequest> {
|
||||
|
||||
private static final String ACTION = "disable-indexing";
|
||||
|
||||
@QueryParam("action")
|
||||
@DefaultValue(ACTION)
|
||||
@Nonnull
|
||||
private String action = ACTION;
|
||||
|
||||
@QueryParam("core")
|
||||
private String core;
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String getCore() {
|
||||
return core;
|
||||
}
|
||||
|
||||
public void setCore(String core) {
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
public DisableIndexingRequest withCore(String core) {
|
||||
this.core = core;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import com.inteligr8.solr.model.JsonFormattedResponseRequest;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
|
||||
public class EnableIndexingRequest extends JsonFormattedResponseRequest<EnableIndexingRequest> {
|
||||
|
||||
private static final String ACTION = "enable-indexing";
|
||||
|
||||
@QueryParam("action")
|
||||
@DefaultValue(ACTION)
|
||||
@Nonnull
|
||||
private String action = ACTION;
|
||||
|
||||
@QueryParam("core")
|
||||
private String core;
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String getCore() {
|
||||
return core;
|
||||
}
|
||||
|
||||
public void setCore(String core) {
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
public EnableIndexingRequest withCore(String core) {
|
||||
this.core = core;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,90 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import com.inteligr8.solr.model.JsonFormattedResponseRequest;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
|
||||
public class FixRequest extends JsonFormattedResponseRequest<FixRequest> {
|
||||
|
||||
private static final String ACTION = "fix";
|
||||
|
||||
@QueryParam("action")
|
||||
@DefaultValue(ACTION)
|
||||
@Nonnull
|
||||
private String action = ACTION;
|
||||
|
||||
@QueryParam("core")
|
||||
private String core;
|
||||
|
||||
@QueryParam("dryRun")
|
||||
private Boolean dryRun;
|
||||
|
||||
@QueryParam("fromTxCommitTime")
|
||||
private Long fromTransactionCommitTime;
|
||||
|
||||
@QueryParam("toTxCommitTime")
|
||||
private Long toTransactionCommitTime;
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String getCore() {
|
||||
return core;
|
||||
}
|
||||
|
||||
public void setCore(String core) {
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
public FixRequest withCore(String core) {
|
||||
this.core = core;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Boolean getDryRun() {
|
||||
return dryRun;
|
||||
}
|
||||
|
||||
public void setDryRun(Boolean dryRun) {
|
||||
this.dryRun = dryRun;
|
||||
}
|
||||
|
||||
public FixRequest dryRun(boolean dryRun) {
|
||||
this.dryRun = dryRun;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Long getFromTransactionCommitTime() {
|
||||
return fromTransactionCommitTime;
|
||||
}
|
||||
|
||||
public void setFromTransactionCommitTime(Long fromTransactionCommitTime) {
|
||||
this.fromTransactionCommitTime = fromTransactionCommitTime;
|
||||
}
|
||||
|
||||
public FixRequest fromTransactionCommitTime(Long fromTransactionCommitTime) {
|
||||
this.fromTransactionCommitTime = fromTransactionCommitTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Long getToTransactionCommitTime() {
|
||||
return toTransactionCommitTime;
|
||||
}
|
||||
|
||||
public void setToTransactionCommitTime(Long toTransactionCommitTime) {
|
||||
this.toTransactionCommitTime = toTransactionCommitTime;
|
||||
}
|
||||
|
||||
public FixRequest toTransactionCommitTime(Long toTransactionCommitTime) {
|
||||
this.toTransactionCommitTime = toTransactionCommitTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty.Access;
|
||||
import com.inteligr8.solr.model.ResponseAction;
|
||||
import com.inteligr8.solr.model.TransactionResponseStatus;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class FixResponseAction extends ResponseAction {
|
||||
|
||||
@JsonProperty(value = "txToReindex", access = Access.READ_ONLY)
|
||||
private TransactionResponseStatus transactionStatus;
|
||||
|
||||
@JsonProperty(value = "aclChangeSetToReindex", access = Access.READ_ONLY)
|
||||
private TransactionResponseStatus aclStatus;
|
||||
|
||||
public TransactionResponseStatus getTransactionStatus() {
|
||||
return transactionStatus;
|
||||
}
|
||||
|
||||
protected void setTransactionStatus(TransactionResponseStatus transactionStatus) {
|
||||
this.transactionStatus = transactionStatus;
|
||||
}
|
||||
|
||||
public TransactionResponseStatus getAclStatus() {
|
||||
return aclStatus;
|
||||
}
|
||||
|
||||
protected void setAclStatus(TransactionResponseStatus aclStatus) {
|
||||
this.aclStatus = aclStatus;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAnyGetter;
|
||||
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.inteligr8.solr.model.ResponseAction;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class IndexingStatusAction extends ResponseAction {
|
||||
|
||||
private Map<String, IndexingStatusMetadata> cores;
|
||||
|
||||
@JsonAnyGetter
|
||||
public Map<String, IndexingStatusMetadata> getCores() {
|
||||
return cores;
|
||||
}
|
||||
|
||||
@JsonAnySetter
|
||||
public void setCores(Map<String, IndexingStatusMetadata> cores) {
|
||||
this.cores = cores;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty.Access;
|
||||
import com.inteligr8.solr.model.ResponseAction;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class IndexingStatusMetadata extends ResponseAction {
|
||||
|
||||
@JsonProperty(value = "ACL", access = Access.READ_ONLY)
|
||||
private Boolean aclIndexed;
|
||||
|
||||
@JsonProperty(value = "CONTENT", access = Access.READ_ONLY)
|
||||
private Boolean contentIndexed;
|
||||
|
||||
@JsonProperty(value = "METADATA", access = Access.READ_ONLY)
|
||||
private Boolean metadataIndexed;
|
||||
|
||||
public boolean isAclIndexed() {
|
||||
return Boolean.TRUE.equals(this.aclIndexed);
|
||||
}
|
||||
|
||||
public Boolean getAclIndexed() {
|
||||
return aclIndexed;
|
||||
}
|
||||
|
||||
protected void setAclIndexed(Boolean aclIndexed) {
|
||||
this.aclIndexed = aclIndexed;
|
||||
}
|
||||
|
||||
public boolean isContentIndexed() {
|
||||
return Boolean.TRUE.equals(this.contentIndexed);
|
||||
}
|
||||
|
||||
public Boolean getContentIndexed() {
|
||||
return contentIndexed;
|
||||
}
|
||||
|
||||
protected void setContentIndexed(Boolean contentIndexed) {
|
||||
this.contentIndexed = contentIndexed;
|
||||
}
|
||||
|
||||
public boolean isMetadataIndexed() {
|
||||
return Boolean.TRUE.equals(this.metadataIndexed);
|
||||
}
|
||||
|
||||
public Boolean getMetadataIndexed() {
|
||||
return metadataIndexed;
|
||||
}
|
||||
|
||||
protected void setMetadataIndexed(Boolean metadataIndexed) {
|
||||
this.metadataIndexed = metadataIndexed;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,161 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.inteligr8.solr.model.JsonFormattedResponseRequest;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
|
||||
public class NewCoreRequest extends JsonFormattedResponseRequest<NewCoreRequest> {
|
||||
|
||||
private static final String ACTION = "newCore";
|
||||
|
||||
@QueryParam("action")
|
||||
@DefaultValue(ACTION)
|
||||
@Nonnull
|
||||
private String action = ACTION;
|
||||
|
||||
@QueryParam("coreName")
|
||||
@Nonnull
|
||||
private String core;
|
||||
|
||||
@QueryParam("storeRef")
|
||||
@Nonnull
|
||||
private StoreRef storeRef;
|
||||
|
||||
@QueryParam("shardIds")
|
||||
private String shardIds;
|
||||
|
||||
@QueryParam("numShards")
|
||||
private Integer shardCount;
|
||||
|
||||
@QueryParam("template")
|
||||
private String template;
|
||||
|
||||
@QueryParam("replicationFactor")
|
||||
private Integer replicationFactor;
|
||||
|
||||
@QueryParam("nodeInstance")
|
||||
private Integer nodeId;
|
||||
|
||||
@QueryParam("numNodes")
|
||||
private Integer nodeCount;
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String getCore() {
|
||||
return core;
|
||||
}
|
||||
|
||||
public void setCore(String core) {
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
public NewCoreRequest withCore(String core) {
|
||||
this.core = core;
|
||||
return this;
|
||||
}
|
||||
|
||||
public StoreRef getStoreRef() {
|
||||
return storeRef;
|
||||
}
|
||||
|
||||
public void setStoreRef(StoreRef storeRef) {
|
||||
this.storeRef = storeRef;
|
||||
}
|
||||
|
||||
public NewCoreRequest withStoreRef(StoreRef storeRef) {
|
||||
this.storeRef = storeRef;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getShardIds() {
|
||||
return shardIds;
|
||||
}
|
||||
|
||||
public void setShardIds(String shardIds) {
|
||||
this.shardIds = shardIds;
|
||||
}
|
||||
|
||||
public NewCoreRequest withShardIds(Collection<String> shardIds) {
|
||||
this.shardIds = StringUtils.join(shardIds, ",");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getShardCount() {
|
||||
return shardCount;
|
||||
}
|
||||
|
||||
public void setShardCount(Integer shardCount) {
|
||||
this.shardCount = shardCount;
|
||||
}
|
||||
|
||||
public NewCoreRequest withShardCount(Integer shardCount) {
|
||||
this.shardCount = shardCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getTemplate() {
|
||||
return template;
|
||||
}
|
||||
|
||||
public void setTemplate(String template) {
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
public NewCoreRequest withTemplate(String template) {
|
||||
this.template = template;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getReplicationFactor() {
|
||||
return replicationFactor;
|
||||
}
|
||||
|
||||
public void setReplicationFactor(Integer replicationFactor) {
|
||||
this.replicationFactor = replicationFactor;
|
||||
}
|
||||
|
||||
public NewCoreRequest withReplicationFactor(Integer replicationFactor) {
|
||||
this.replicationFactor = replicationFactor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getNodeId() {
|
||||
return nodeId;
|
||||
}
|
||||
|
||||
public void setNodeId(Integer nodeId) {
|
||||
this.nodeId = nodeId;
|
||||
}
|
||||
|
||||
public NewCoreRequest withNodeId(Integer nodeId) {
|
||||
this.nodeId = nodeId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getNodeCount() {
|
||||
return nodeCount;
|
||||
}
|
||||
|
||||
public void setNodeCount(Integer nodeCount) {
|
||||
this.nodeCount = nodeCount;
|
||||
}
|
||||
|
||||
public NewCoreRequest withNodeCount(Integer nodeCount) {
|
||||
this.nodeCount = nodeCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,78 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
|
||||
import com.inteligr8.solr.model.JsonFormattedResponseRequest;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
|
||||
public class NewDefaultIndexRequest extends JsonFormattedResponseRequest<NewDefaultIndexRequest> {
|
||||
|
||||
private static final String ACTION = "newDefaultIndex";
|
||||
|
||||
@QueryParam("action")
|
||||
@DefaultValue(ACTION)
|
||||
@Nonnull
|
||||
public String action = ACTION;
|
||||
|
||||
@QueryParam("coreName")
|
||||
@Nonnull
|
||||
public String core;
|
||||
|
||||
@QueryParam("storeRef")
|
||||
@Nonnull
|
||||
public StoreRef storeRef;
|
||||
|
||||
@QueryParam("template")
|
||||
public String template;
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
protected void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String getCore() {
|
||||
return core;
|
||||
}
|
||||
|
||||
public void setCore(String core) {
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
public NewDefaultIndexRequest withCore(String core) {
|
||||
this.core = core;
|
||||
return this;
|
||||
}
|
||||
|
||||
public StoreRef getStoreRef() {
|
||||
return storeRef;
|
||||
}
|
||||
|
||||
public void setStoreRef(StoreRef storeRef) {
|
||||
this.storeRef = storeRef;
|
||||
}
|
||||
|
||||
public NewDefaultIndexRequest withStoreRef(StoreRef storeRef) {
|
||||
this.storeRef = storeRef;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getTemplate() {
|
||||
return template;
|
||||
}
|
||||
|
||||
public void setTemplate(String template) {
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
public NewDefaultIndexRequest withTemplate(String template) {
|
||||
this.template = template;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,106 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import com.inteligr8.solr.model.JsonFormattedResponseRequest;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
|
||||
public class PurgeRequest extends JsonFormattedResponseRequest<PurgeRequest> {
|
||||
|
||||
private static final String ACTION = "purge";
|
||||
|
||||
@QueryParam("action")
|
||||
@DefaultValue(ACTION)
|
||||
@Nonnull
|
||||
private String action = ACTION;
|
||||
|
||||
@QueryParam("core")
|
||||
private String core;
|
||||
|
||||
@QueryParam("txid")
|
||||
private Integer transactionId;
|
||||
|
||||
@QueryParam("acltxid")
|
||||
private Integer aclTransactionId;
|
||||
|
||||
@QueryParam("nodeId")
|
||||
private Integer nodeId;
|
||||
|
||||
@QueryParam("aclid")
|
||||
private Integer aclId;
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String getCore() {
|
||||
return core;
|
||||
}
|
||||
|
||||
public void setCore(String core) {
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
public PurgeRequest withCore(String core) {
|
||||
this.core = core;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getTransactionId() {
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
public void setTransactionId(Integer transactionId) {
|
||||
this.transactionId = transactionId;
|
||||
}
|
||||
|
||||
public PurgeRequest withTransactionId(Integer transactionId) {
|
||||
this.transactionId = transactionId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getAclTransactionId() {
|
||||
return aclTransactionId;
|
||||
}
|
||||
|
||||
public void setAclTransactionId(Integer aclTransactionId) {
|
||||
this.aclTransactionId = aclTransactionId;
|
||||
}
|
||||
|
||||
public PurgeRequest withAclTransactionId(Integer aclTransactionId) {
|
||||
this.aclTransactionId = aclTransactionId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getNodeId() {
|
||||
return nodeId;
|
||||
}
|
||||
|
||||
public void setNodeId(Integer nodeId) {
|
||||
this.nodeId = nodeId;
|
||||
}
|
||||
|
||||
public PurgeRequest withNodeId(Integer nodeId) {
|
||||
this.nodeId = nodeId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getAclId() {
|
||||
return aclId;
|
||||
}
|
||||
|
||||
public void setAclId(Integer aclId) {
|
||||
this.aclId = aclId;
|
||||
}
|
||||
|
||||
public PurgeRequest withAclId(Integer aclId) {
|
||||
this.aclId = aclId;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,122 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import com.inteligr8.solr.model.JsonFormattedResponseRequest;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
|
||||
public class ReindexRequest extends JsonFormattedResponseRequest<ReindexRequest> {
|
||||
|
||||
private static final String ACTION = "reindex";
|
||||
|
||||
@QueryParam("action")
|
||||
@DefaultValue(ACTION)
|
||||
@Nonnull
|
||||
private String action = ACTION;
|
||||
|
||||
@QueryParam("core")
|
||||
private String core;
|
||||
|
||||
@QueryParam("txid")
|
||||
private Integer transactionId;
|
||||
|
||||
@QueryParam("acltxid")
|
||||
private Integer aclTransactionId;
|
||||
|
||||
@QueryParam("nodeId")
|
||||
private Integer nodeId;
|
||||
|
||||
@QueryParam("aclid")
|
||||
private Integer aclId;
|
||||
|
||||
@QueryParam("query")
|
||||
private String query;
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String getCore() {
|
||||
return core;
|
||||
}
|
||||
|
||||
public void setCore(String core) {
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
public ReindexRequest withCore(String core) {
|
||||
this.core = core;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getTransactionId() {
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
public void setTransactionId(Integer transactionId) {
|
||||
this.transactionId = transactionId;
|
||||
}
|
||||
|
||||
public ReindexRequest withTransactionId(Integer transactionId) {
|
||||
this.transactionId = transactionId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getAclTransactionId() {
|
||||
return aclTransactionId;
|
||||
}
|
||||
|
||||
public void setAclTransactionId(Integer aclTransactionId) {
|
||||
this.aclTransactionId = aclTransactionId;
|
||||
}
|
||||
|
||||
public ReindexRequest withAclTransactionId(Integer aclTransactionId) {
|
||||
this.aclTransactionId = aclTransactionId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getNodeId() {
|
||||
return nodeId;
|
||||
}
|
||||
|
||||
public void setNodeId(Integer nodeId) {
|
||||
this.nodeId = nodeId;
|
||||
}
|
||||
|
||||
public ReindexRequest withNodeId(Integer nodeId) {
|
||||
this.nodeId = nodeId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getAclId() {
|
||||
return aclId;
|
||||
}
|
||||
|
||||
public void setAclId(Integer aclId) {
|
||||
this.aclId = aclId;
|
||||
}
|
||||
|
||||
public ReindexRequest withAclId(Integer aclId) {
|
||||
this.aclId = aclId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getQuery() {
|
||||
return query;
|
||||
}
|
||||
|
||||
public void setQuery(String query) {
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
public ReindexRequest withQuery(String query) {
|
||||
this.query = query;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAnyGetter;
|
||||
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Report {
|
||||
|
||||
private Map<String, Map<String, Object>> report;
|
||||
|
||||
@JsonAnyGetter
|
||||
public Map<String, Map<String, Object>> getReport() {
|
||||
return report;
|
||||
}
|
||||
|
||||
@JsonAnySetter
|
||||
protected void setReport(Map<String, Map<String, Object>> report) {
|
||||
this.report = report;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,106 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import com.inteligr8.solr.model.JsonFormattedResponseRequest;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
|
||||
public class ReportRequest extends JsonFormattedResponseRequest<ReportRequest> {
|
||||
|
||||
private static final String ACTION = "report";
|
||||
|
||||
@QueryParam("action")
|
||||
@DefaultValue(ACTION)
|
||||
@Nonnull
|
||||
private String action = ACTION;
|
||||
|
||||
@QueryParam("core")
|
||||
private String core;
|
||||
|
||||
@QueryParam("fromTime")
|
||||
private Long fromTime;
|
||||
|
||||
@QueryParam("toTime")
|
||||
private Long toTime;
|
||||
|
||||
@QueryParam("fromTx")
|
||||
private Integer fromTransactionId;
|
||||
|
||||
@QueryParam("toTx")
|
||||
private Integer toTransactionId;
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String getCore() {
|
||||
return core;
|
||||
}
|
||||
|
||||
public void setCore(String core) {
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
public ReportRequest withCore(String core) {
|
||||
this.core = core;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Long getFromTime() {
|
||||
return fromTime;
|
||||
}
|
||||
|
||||
public void setFromTime(Long fromTime) {
|
||||
this.fromTime = fromTime;
|
||||
}
|
||||
|
||||
public ReportRequest fromTime(Long fromTime) {
|
||||
this.fromTime = fromTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Long getToTime() {
|
||||
return toTime;
|
||||
}
|
||||
|
||||
public void setToTime(Long toTime) {
|
||||
this.toTime = toTime;
|
||||
}
|
||||
|
||||
public ReportRequest toTime(Long toTime) {
|
||||
this.toTime = toTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getFromTransactionId() {
|
||||
return fromTransactionId;
|
||||
}
|
||||
|
||||
public void setFromTransactionId(Integer fromTransactionId) {
|
||||
this.fromTransactionId = fromTransactionId;
|
||||
}
|
||||
|
||||
public ReportRequest fromTransactionId(Integer fromTransactionId) {
|
||||
this.fromTransactionId = fromTransactionId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getToTransactionId() {
|
||||
return toTransactionId;
|
||||
}
|
||||
|
||||
public void setToTransactionId(Integer toTransactionId) {
|
||||
this.toTransactionId = toTransactionId;
|
||||
}
|
||||
|
||||
public ReportRequest toTransactionId(Integer toTransactionId) {
|
||||
this.toTransactionId = toTransactionId;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty.Access;
|
||||
import com.inteligr8.alfresco.asie.model.BaseResponse;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ReportResponse extends BaseResponse {
|
||||
|
||||
@JsonProperty(access = Access.READ_ONLY)
|
||||
private Report report;
|
||||
|
||||
public Report getReport() {
|
||||
return report;
|
||||
}
|
||||
|
||||
protected void setReport(Report report) {
|
||||
this.report = report;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import com.inteligr8.solr.model.JsonFormattedResponseRequest;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
|
||||
public class RetryRequest extends JsonFormattedResponseRequest<RetryRequest> {
|
||||
|
||||
private static final String ACTION = "retry";
|
||||
|
||||
@QueryParam("action")
|
||||
@DefaultValue(ACTION)
|
||||
@Nonnull
|
||||
private String action = ACTION;
|
||||
|
||||
@QueryParam("core")
|
||||
private String core;
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String getCore() {
|
||||
return core;
|
||||
}
|
||||
|
||||
public void setCore(String core) {
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
public RetryRequest withCore(String core) {
|
||||
this.core = core;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty.Access;
|
||||
import com.inteligr8.solr.model.ResponseAction;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class RetryResponseAction extends ResponseAction {
|
||||
|
||||
@JsonProperty(value = "alfresco", access = Access.READ_ONLY)
|
||||
private int[] nodeIds;
|
||||
|
||||
public int[] getNodeIds() {
|
||||
return nodeIds;
|
||||
}
|
||||
|
||||
public void setNodeIds(int[] nodeIds) {
|
||||
this.nodeIds = nodeIds;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAnyGetter;
|
||||
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Summary {
|
||||
|
||||
private Map<String, Object> summary;
|
||||
|
||||
@JsonAnyGetter
|
||||
public Map<String, Object> getSummary() {
|
||||
return summary;
|
||||
}
|
||||
|
||||
@JsonAnySetter
|
||||
public void setSummary(Map<String, Object> summary) {
|
||||
this.summary = summary;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,107 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import com.inteligr8.solr.model.JsonFormattedResponseRequest;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
|
||||
public class SummaryRequest extends JsonFormattedResponseRequest<SummaryRequest> {
|
||||
|
||||
private static final String ACTION = "summary";
|
||||
|
||||
@QueryParam("action")
|
||||
@DefaultValue(ACTION)
|
||||
@Nonnull
|
||||
private String action = ACTION;
|
||||
|
||||
@QueryParam("core")
|
||||
@Nonnull
|
||||
private String core;
|
||||
|
||||
@QueryParam("detail")
|
||||
private Boolean includeDetails;
|
||||
|
||||
@QueryParam("hist")
|
||||
private Boolean includeHistogram;
|
||||
|
||||
@QueryParam("values")
|
||||
private Boolean includeSomeValues;
|
||||
|
||||
@QueryParam("reset")
|
||||
private Boolean resetStats;
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String getCore() {
|
||||
return core;
|
||||
}
|
||||
|
||||
public void setCore(String core) {
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
public SummaryRequest withCore(String core) {
|
||||
this.core = core;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Boolean getIncludeDetails() {
|
||||
return includeDetails;
|
||||
}
|
||||
|
||||
public void setIncludeDetails(Boolean includeDetails) {
|
||||
this.includeDetails = includeDetails;
|
||||
}
|
||||
|
||||
public SummaryRequest includeDetails(boolean includeDetails) {
|
||||
this.includeDetails = includeDetails;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Boolean getIncludeHistogram() {
|
||||
return includeHistogram;
|
||||
}
|
||||
|
||||
public void setIncludeHistogram(Boolean includeHistogram) {
|
||||
this.includeHistogram = includeHistogram;
|
||||
}
|
||||
|
||||
public SummaryRequest includeHistogram(boolean includeHistogram) {
|
||||
this.includeHistogram = includeHistogram;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Boolean getIncludeSomeValues() {
|
||||
return includeSomeValues;
|
||||
}
|
||||
|
||||
public void setIncludeSomeValues(Boolean includeSomeValues) {
|
||||
this.includeSomeValues = includeSomeValues;
|
||||
}
|
||||
|
||||
public SummaryRequest includeSomeValues(boolean includeSomeValues) {
|
||||
this.includeSomeValues = includeSomeValues;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Boolean getResetStats() {
|
||||
return resetStats;
|
||||
}
|
||||
|
||||
public void setResetStats(Boolean resetStats) {
|
||||
this.resetStats = resetStats;
|
||||
}
|
||||
|
||||
public SummaryRequest resetStats(boolean resetStats) {
|
||||
this.resetStats = resetStats;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty.Access;
|
||||
import com.inteligr8.alfresco.asie.model.BaseResponse;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class SummaryResponse extends BaseResponse {
|
||||
|
||||
@JsonProperty(value = "Summary", access = Access.READ_ONLY)
|
||||
private Summary summary;
|
||||
|
||||
public Summary getSummary() {
|
||||
return summary;
|
||||
}
|
||||
|
||||
public void setSummary(Summary summary) {
|
||||
this.summary = summary;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import com.inteligr8.solr.model.JsonFormattedResponseRequest;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
|
||||
public class UpdateCoreRequest extends JsonFormattedResponseRequest<UpdateCoreRequest> {
|
||||
|
||||
private static final String ACTION = "updateCore";
|
||||
|
||||
@QueryParam("action")
|
||||
@DefaultValue(ACTION)
|
||||
@Nonnull
|
||||
private String action = ACTION;
|
||||
|
||||
@QueryParam("coreName")
|
||||
@Nonnull
|
||||
private String core;
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String getCore() {
|
||||
return core;
|
||||
}
|
||||
|
||||
public void setCore(String core) {
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
public UpdateCoreRequest withCore(String core) {
|
||||
this.core = core;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import com.inteligr8.solr.model.JsonFormattedResponseRequest;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
|
||||
public class UpdateLog4jRequest extends JsonFormattedResponseRequest<UpdateLog4jRequest> {
|
||||
|
||||
private static final String ACTION = "log4j";
|
||||
|
||||
@QueryParam("action")
|
||||
@DefaultValue(ACTION)
|
||||
@Nonnull
|
||||
private String action = ACTION;
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
package com.inteligr8.alfresco.asie.model.core;
|
||||
|
||||
import com.inteligr8.solr.model.JsonFormattedResponseRequest;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
|
||||
public class UpdateSharedRequest extends JsonFormattedResponseRequest<UpdateSharedRequest> {
|
||||
|
||||
private static final String ACTION = "updateShared";
|
||||
|
||||
@QueryParam("action")
|
||||
@DefaultValue(ACTION)
|
||||
@Nonnull
|
||||
private String action = ACTION;
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
}
|
12
module/.gitignore
vendored
Normal file
12
module/.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# Maven
|
||||
target
|
||||
pom.xml.versionsBackup
|
||||
|
||||
# Eclipse
|
||||
.project
|
||||
.classpath
|
||||
.settings
|
||||
.vscode
|
||||
|
||||
# IDEA
|
||||
/.idea/
|
1
module/README.md
Normal file
1
module/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# ASIE Platform Module Library
|
182
module/pom.xml
Normal file
182
module/pom.xml
Normal file
@@ -0,0 +1,182 @@
|
||||
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.inteligr8.alfresco</groupId>
|
||||
<artifactId>asie-platform-module-parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>asie-platform-module</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ASIE Platform Module</name>
|
||||
|
||||
<properties>
|
||||
<alfresco.sdk.version>5.2.0</alfresco.sdk.version>
|
||||
<alfresco.platform.version>23.3.2</alfresco.platform.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>acs-packaging</artifactId>
|
||||
<version>${alfresco.platform.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Provided by ACS, but packaged due to common-rest-client -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.annotation</groupId>
|
||||
<artifactId>jakarta.annotation-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.ws.rs</groupId>
|
||||
<artifactId>jakarta.ws.rs-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.jakarta.rs</groupId>
|
||||
<artifactId>jackson-jakarta-rs-json-provider</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.cxf</groupId>
|
||||
<artifactId>cxf-rt-rs-client</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.inteligr8.alfresco</groupId>
|
||||
<artifactId>asie-api</artifactId>
|
||||
<version>1.0-SNAPSHOT-asie2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.inteligr8</groupId>
|
||||
<artifactId>common-rest-client</artifactId>
|
||||
<version>3.0.1-cxf</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Needed by this module, but provided by ACS -->
|
||||
<dependency>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-enterprise-repository</artifactId>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-elasticsearch-shared</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-repository</artifactId>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<!-- JDK 9+ Eclipse build issue -->
|
||||
<exclusion>
|
||||
<groupId>xpp3</groupId>
|
||||
<artifactId>xpp3</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Alfresco Modules required to use this module -->
|
||||
<dependency>
|
||||
<groupId>com.inteligr8.alfresco</groupId>
|
||||
<artifactId>cxf-jaxrs-platform-module</artifactId>
|
||||
<version>1.2.0-acs-v23.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Including for testing purposes only -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<!-- avoids log4j dependency -->
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.13.0</version>
|
||||
</plugin>
|
||||
<!-- avoids struts dependency -->
|
||||
<plugin>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>3.12.1</version>
|
||||
</plugin>
|
||||
<!-- Force use of a new maven-dependency-plugin that doesn't download struts dependency -->
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>3.7.1</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>io.repaint.maven</groupId>
|
||||
<artifactId>tiles-maven-plugin</artifactId>
|
||||
<version>2.40</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<tiles>
|
||||
<!-- Documentation: https://bitbucket.org/inteligr8/ootbee-beedk/src/stable/beedk-acs-platform-module-tile -->
|
||||
<tile>com.inteligr8.ootbee:beedk-acs-platform-module-tile:[1.1.6,2.0.0)</tile>
|
||||
</tiles>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>alfresco-private</id>
|
||||
<url>https://artifacts.alfresco.com/nexus/content/groups/private</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
</project>
|
74
module/rad.ps1
Normal file
74
module/rad.ps1
Normal file
@@ -0,0 +1,74 @@
|
||||
|
||||
function discoverArtifactId {
|
||||
$script:ARTIFACT_ID=(mvn -q -Dexpression=project"."artifactId -DforceStdout help:evaluate)
|
||||
}
|
||||
|
||||
function rebuild {
|
||||
echo "Rebuilding project ..."
|
||||
mvn process-classes
|
||||
}
|
||||
|
||||
function start_ {
|
||||
echo "Rebuilding project and starting Docker containers to support rapid application development ..."
|
||||
mvn -Drad process-classes
|
||||
}
|
||||
|
||||
function start_log {
|
||||
echo "Rebuilding project and starting Docker containers to support rapid application development ..."
|
||||
mvn -Drad "-Ddocker.showLogs" process-classes
|
||||
}
|
||||
|
||||
function stop_ {
|
||||
discoverArtifactId
|
||||
echo "Stopping Docker containers that supported rapid application development ..."
|
||||
docker container ls --filter name=${ARTIFACT_ID}-*
|
||||
echo "Stopping containers ..."
|
||||
docker container stop (docker container ls -q --filter name=${ARTIFACT_ID}-*)
|
||||
echo "Removing containers ..."
|
||||
docker container rm (docker container ls -aq --filter name=${ARTIFACT_ID}-*)
|
||||
}
|
||||
|
||||
function tail_logs {
|
||||
param (
|
||||
$container
|
||||
)
|
||||
|
||||
discoverArtifactId
|
||||
docker container logs -f (docker container ls -q --filter name=${ARTIFACT_ID}-${container})
|
||||
}
|
||||
|
||||
function list {
|
||||
discoverArtifactId
|
||||
docker container ls --filter name=${ARTIFACT_ID}-*
|
||||
}
|
||||
|
||||
switch ($args[0]) {
|
||||
"start" {
|
||||
start_
|
||||
}
|
||||
"start_log" {
|
||||
start_log
|
||||
}
|
||||
"stop" {
|
||||
stop_
|
||||
}
|
||||
"restart" {
|
||||
stop_
|
||||
start_
|
||||
}
|
||||
"rebuild" {
|
||||
rebuild
|
||||
}
|
||||
"tail" {
|
||||
tail_logs $args[1]
|
||||
}
|
||||
"containers" {
|
||||
list
|
||||
}
|
||||
default {
|
||||
echo "Usage: .\rad.ps1 [ start | start_log | stop | restart | rebuild | tail {container} | containers ]"
|
||||
}
|
||||
}
|
||||
|
||||
echo "Completed!"
|
||||
|
71
module/rad.sh
Normal file
71
module/rad.sh
Normal file
@@ -0,0 +1,71 @@
|
||||
#!/bin/sh
|
||||
|
||||
discoverArtifactId() {
|
||||
ARTIFACT_ID=`mvn -q -Dexpression=project.artifactId -DforceStdout help:evaluate`
|
||||
}
|
||||
|
||||
rebuild() {
|
||||
echo "Rebuilding project ..."
|
||||
mvn process-classes
|
||||
}
|
||||
|
||||
start() {
|
||||
echo "Rebuilding project and starting Docker containers to support rapid application development ..."
|
||||
mvn -Drad process-classes
|
||||
}
|
||||
|
||||
start_log() {
|
||||
echo "Rebuilding project and starting Docker containers to support rapid application development ..."
|
||||
mvn -Drad -Ddocker.showLogs process-classes
|
||||
}
|
||||
|
||||
stop() {
|
||||
discoverArtifactId
|
||||
echo "Stopping Docker containers that supported rapid application development ..."
|
||||
docker container ls --filter name=${ARTIFACT_ID}-*
|
||||
echo "Stopping containers ..."
|
||||
docker container stop `docker container ls -q --filter name=${ARTIFACT_ID}-*`
|
||||
echo "Removing containers ..."
|
||||
docker container rm `docker container ls -aq --filter name=${ARTIFACT_ID}-*`
|
||||
}
|
||||
|
||||
tail_logs() {
|
||||
discoverArtifactId
|
||||
docker container logs -f `docker container ls -q --filter name=${ARTIFACT_ID}-$1`
|
||||
}
|
||||
|
||||
list() {
|
||||
discoverArtifactId
|
||||
docker container ls --filter name=${ARTIFACT_ID}-*
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
start_log)
|
||||
start_log
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
restart)
|
||||
stop
|
||||
start
|
||||
;;
|
||||
rebuild)
|
||||
rebuild
|
||||
;;
|
||||
tail)
|
||||
tail_logs $2
|
||||
;;
|
||||
containers)
|
||||
list
|
||||
;;
|
||||
*)
|
||||
echo "Usage: ./rad.sh [ start | start_log | stop | restart | rebuild | tail {container} | containers ]"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
echo "Completed!"
|
||||
|
114
module/research/acs-enterprise-shard-attributes.json
Normal file
114
module/research/acs-enterprise-shard-attributes.json
Normal file
@@ -0,0 +1,114 @@
|
||||
{
|
||||
".SHARD_STATE": {
|
||||
"d2fda078-887c-46a3-bda0-78887c06a305": {
|
||||
"type": "ShardState",
|
||||
"shardInstance": {
|
||||
"type": "ShardInstance",
|
||||
"shard": {
|
||||
"type": "Shard",
|
||||
"floc": {
|
||||
"type": "Floc",
|
||||
"storeRefs": [
|
||||
"workspace://SpacesStore"
|
||||
],
|
||||
"numberOfShards": 32,
|
||||
"shardMethod": "PROPERTY",
|
||||
"template": "rerank",
|
||||
"hasContent": true,
|
||||
"propertyBag": {}
|
||||
},
|
||||
"instance": 29
|
||||
},
|
||||
"baseUrl": "/solr/alfresco-year-29",
|
||||
"port": 8983,
|
||||
"hostName": "localhost"
|
||||
},
|
||||
"isMaster": true,
|
||||
"lastUpdated": 1729099258001,
|
||||
"lastIndexedChangeSetId": 1189,
|
||||
"lastIndexedTxCommitTime": 1729098871726,
|
||||
"lastIndexedTxId": 524708,
|
||||
"lastIndexedChangeSetCommitTime": 1729010974050,
|
||||
"propertyBag": {
|
||||
"shard.key": "cm:created",
|
||||
"shard.regex": "^(\\d{4})",
|
||||
"coreName": "alfresco-year-29"
|
||||
}
|
||||
},
|
||||
"8cd7436d-787a-478a-9743-6d787a778a1f": {
|
||||
"type": "ShardState",
|
||||
"shardInstance": {
|
||||
"type": "ShardInstance",
|
||||
"shard": {
|
||||
"type": "Shard",
|
||||
"floc": {
|
||||
"type": "Floc",
|
||||
"storeRefs": [
|
||||
"workspace://SpacesStore"
|
||||
],
|
||||
"numberOfShards": 32,
|
||||
"shardMethod": "PROPERTY",
|
||||
"template": "rerank",
|
||||
"hasContent": true,
|
||||
"propertyBag": {}
|
||||
},
|
||||
"instance": 0
|
||||
},
|
||||
"baseUrl": "/solr/alfresco-year-0",
|
||||
"port": 8983,
|
||||
"hostName": "localhost"
|
||||
},
|
||||
"isMaster": true,
|
||||
"lastUpdated": 1729099258001,
|
||||
"lastIndexedChangeSetId": 1189,
|
||||
"lastIndexedTxCommitTime": 1729098871726,
|
||||
"lastIndexedTxId": 524708,
|
||||
"lastIndexedChangeSetCommitTime": 1729010974050,
|
||||
"propertyBag": {
|
||||
"shard.key": "cm:created",
|
||||
"shard.regex": "^(\\d{4})",
|
||||
"coreName": "alfresco-year-29"
|
||||
}
|
||||
},
|
||||
"ae5e918d-c602-4bb0-9e91-8dc6028bb088": {
|
||||
"type": "ShardState",
|
||||
"shardInstance": {
|
||||
"type": "ShardInstance",
|
||||
"shard": {
|
||||
"type": "Shard",
|
||||
"floc": {
|
||||
"type": "Floc",
|
||||
"storeRefs": [
|
||||
"workspace://SpacesStore"
|
||||
],
|
||||
"numberOfShards": 32,
|
||||
"shardMethod": "PROPERTY",
|
||||
"template": "rerank",
|
||||
"hasContent": true,
|
||||
"propertyBag": {}
|
||||
},
|
||||
"instance": 1
|
||||
},
|
||||
"baseUrl": "/solr/alfresco-year-1",
|
||||
"port": 8983,
|
||||
"hostName": "localhost"
|
||||
},
|
||||
"isMaster": true,
|
||||
"lastUpdated": 1729099258001,
|
||||
"lastIndexedChangeSetId": 1189,
|
||||
"lastIndexedTxCommitTime": 1729098871726,
|
||||
"lastIndexedTxId": 524708,
|
||||
"lastIndexedChangeSetCommitTime": 1729010974050,
|
||||
"propertyBag": {
|
||||
"shard.key": "cm:created",
|
||||
"shard.regex": "^(\\d{4})",
|
||||
"coreName": "alfresco-year-29"
|
||||
}
|
||||
}
|
||||
},
|
||||
".SHARD_SUBSCRIPTION": {
|
||||
"8cd7436d-787a-478a-9743-6d787a778a1f": "Shard #0 subscribed on Wed Oct 16 17:20:07 UTC 2024 (timestamp = 1729099207319)",
|
||||
"ae5e918d-c602-4bb0-9e91-8dc6028bb088": "Shard #1 subscribed on Wed Oct 16 17:20:08 UTC 2024 (timestamp = 1729099208026)"
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,13 @@
|
||||
package com.inteligr8.alfresco.asie;
|
||||
|
||||
public interface Constants {
|
||||
|
||||
static final String QUALIFIER_ASIE = "asie";
|
||||
static final String BEAN_SOLR_ADMIN_CLIENT = "search.SolrAdminClient";
|
||||
static final String BEAN_SHARD_REGISTRY = "search.ShardRegistry";
|
||||
static final String ATTR_SHARD_STATE = ".SHARD_STATE";
|
||||
static final String ATTR_SHARD_SUBSCRIPTION = ".SHARD_SUBSCRIPTION";
|
||||
static final String ATTR_ASIE = "inteligr8.asie";
|
||||
static final String ATTR_UNLOADED_NODE_CORES = "unloadedNode.cores";
|
||||
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
package com.inteligr8.alfresco.asie.compute;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.inteligr8.alfresco.asie.service.SolrShardHashService;
|
||||
|
||||
@Component
|
||||
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
||||
public class SolrShardEnumeratedHashTable extends SolrShardHashTable<Object> {
|
||||
|
||||
/**
|
||||
* For Spring use only
|
||||
*/
|
||||
public SolrShardEnumeratedHashTable(int shards) {
|
||||
super(shards);
|
||||
}
|
||||
|
||||
/**
|
||||
* For non-Spring use
|
||||
*/
|
||||
public SolrShardEnumeratedHashTable(int shards, SolrShardHashService sshs) {
|
||||
super(shards, sshs);
|
||||
}
|
||||
|
||||
public SolrShardEnumeratedHashTable build(Collection<?> objs) {
|
||||
for (Object obj : objs) {
|
||||
int hashed = this.hashForward(obj);
|
||||
|
||||
Set<Object> ns = this.reverseHash.get(hashed);
|
||||
if (ns == null)
|
||||
this.reverseHash.put(hashed, ns = new HashSet<>());
|
||||
ns.add(obj);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public SolrShardEnumeratedHashTable build(Object... objs) {
|
||||
for (Object obj : objs) {
|
||||
int hashed = this.hashForward(obj);
|
||||
|
||||
Set<Object> ns = this.reverseHash.get(hashed);
|
||||
if (ns == null)
|
||||
this.reverseHash.put(hashed, ns = new HashSet<>());
|
||||
ns.add(obj);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
package com.inteligr8.alfresco.asie.compute;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import com.inteligr8.alfresco.asie.service.SolrShardHashService;
|
||||
|
||||
public class SolrShardHashTable<T> {
|
||||
|
||||
private final int shards;
|
||||
protected Map<Integer, Set<T>> reverseHash;
|
||||
|
||||
@Autowired
|
||||
private SolrShardHashService sshs;
|
||||
|
||||
/**
|
||||
* For Spring use only
|
||||
*/
|
||||
public SolrShardHashTable(int shards) {
|
||||
this.shards = shards;
|
||||
this.reverseHash = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* For non-Spring use
|
||||
*/
|
||||
public SolrShardHashTable(int shards, SolrShardHashService sshs) {
|
||||
this(shards);
|
||||
this.sshs = sshs;
|
||||
}
|
||||
|
||||
public int hashForward(Object obj) {
|
||||
return this.sshs.hash(obj, this.shards);
|
||||
}
|
||||
|
||||
public Set<T> hashReverse(int hash) {
|
||||
return this.reverseHash.get(hash);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
package com.inteligr8.alfresco.asie.compute;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.inteligr8.alfresco.asie.service.SolrShardHashService;
|
||||
|
||||
@Component
|
||||
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
||||
public class SolrShardNumericHashTable extends SolrShardHashTable<Long> {
|
||||
|
||||
/**
|
||||
* For Spring use only
|
||||
*/
|
||||
public SolrShardNumericHashTable(int shards) {
|
||||
super(shards);
|
||||
}
|
||||
|
||||
/**
|
||||
* For non-Spring use
|
||||
*/
|
||||
public SolrShardNumericHashTable(int shards, SolrShardHashService sshs) {
|
||||
super(shards, sshs);
|
||||
}
|
||||
|
||||
public SolrShardNumericHashTable build(long start, long end) {
|
||||
for (long n = start; n <= end; n++) {
|
||||
int hashed = this.hashForward(n);
|
||||
|
||||
Set<Long> ns = this.reverseHash.get(hashed);
|
||||
if (ns == null)
|
||||
this.reverseHash.put(hashed, ns = new HashSet<>());
|
||||
ns.add(n);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.bootstrap;
|
||||
|
||||
import org.alfresco.service.cmr.attributes.AttributeService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.inteligr8.alfresco.asie.Constants;
|
||||
|
||||
/**
|
||||
* This is a workaround to a bug with the Alfresco Enterprise Solr purge
|
||||
* functionality, letting it fail due to a concurrency exception. This skips
|
||||
* all the fancy stuff and just hard purges the shards.
|
||||
*/
|
||||
@Component
|
||||
public class ShardPurgeService extends AbstractLifecycleBean {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Autowired
|
||||
@Qualifier(Constants.QUALIFIER_ASIE)
|
||||
private AttributeService attributeService;
|
||||
|
||||
@Value("${search.solrShardRegistry.purgeOnInit}")
|
||||
private boolean enabled;
|
||||
|
||||
@Override
|
||||
protected void onBootstrap(ApplicationEvent event) {
|
||||
this.logger.info("Using workaround for Alfresco Enterprise Solr ShardRegistry purge");
|
||||
this.attributeService.removeAttributes(Constants.ATTR_SHARD_STATE);
|
||||
this.attributeService.removeAttributes(Constants.ATTR_SHARD_SUBSCRIPTION);
|
||||
this.attributeService.removeAttributes(Constants.ATTR_ASIE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onShutdown(ApplicationEvent event) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.model;
|
||||
|
||||
import com.inteligr8.alfresco.asie.model.NodeParameterSet;
|
||||
|
||||
public class NodeShardParameterSet extends NodeParameterSet {
|
||||
|
||||
private ShardSet shardSet;
|
||||
private int shardId;
|
||||
|
||||
public NodeShardParameterSet(String nodeHostname, int nodePort, ShardSet shardSet, int shardId) {
|
||||
super(nodeHostname, nodePort);
|
||||
this.shardSet = shardSet;
|
||||
this.shardId = shardId;
|
||||
}
|
||||
|
||||
public ShardSet getShardSet() {
|
||||
return shardSet;
|
||||
}
|
||||
|
||||
public int getShardId() {
|
||||
return shardId;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.model;
|
||||
|
||||
import com.inteligr8.alfresco.asie.model.RequestParameterSet;
|
||||
|
||||
public class ShardParameterSet implements RequestParameterSet {
|
||||
|
||||
private ShardSet set;
|
||||
private int id;
|
||||
|
||||
public ShardParameterSet(ShardSet set, int id) {
|
||||
this.set = set;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public ShardSet getSet() {
|
||||
return set;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,115 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.model;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.alfresco.repo.index.shard.Floc;
|
||||
import org.alfresco.repo.index.shard.ShardMethodEnum;
|
||||
import org.alfresco.repo.index.shard.ShardState;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
|
||||
public class ShardSet {
|
||||
|
||||
/**
|
||||
* Examples:
|
||||
*
|
||||
* MOD_ACL_ID
|
||||
* ACL_ID
|
||||
* DB_ID
|
||||
* DB_ID_RANGE;range:0-20000
|
||||
* DATE;key:cm:created
|
||||
* DATE;key:cm:created;date.grouping:3
|
||||
* PROPERTY;key:cm:created;regex:^d{4}
|
||||
*/
|
||||
private final Pattern shardSetPattern = Pattern.compile("([A-Z]+)(;fulltext)?(;([a-z]+):([^;]+))?(;([a-z]+):([^;]+))?");
|
||||
|
||||
private final ShardMethodEnum method;
|
||||
private final boolean hasContent;
|
||||
private final Map<String, String> config;
|
||||
private Integer hash;
|
||||
|
||||
public ShardSet(Floc floc, ShardState anyShardNode) {
|
||||
this.method = floc.getShardMethod();
|
||||
this.hasContent = floc.hasContent();
|
||||
this.config = (floc.getPropertyBag().isEmpty() && anyShardNode != null) ? anyShardNode.getPropertyBag() : floc.getPropertyBag();
|
||||
}
|
||||
|
||||
public ShardSet(String shardSetSpec) {
|
||||
Matcher matcher = this.shardSetPattern.matcher(shardSetSpec);
|
||||
if (!matcher.find())
|
||||
throw new IllegalArgumentException("The shard set '" + shardSetSpec + "' is not properly formatted");
|
||||
|
||||
this.method = ShardMethodEnum.valueOf(matcher.group(1));
|
||||
this.hasContent = ";fulltext".equals(matcher.group(2));
|
||||
this.config = new HashMap<>();
|
||||
for (int g = 3; g < matcher.groupCount(); g += 3)
|
||||
if (matcher.group(g) != null)
|
||||
this.config.put("shard." + matcher.group(g+1), matcher.group(g+2));
|
||||
}
|
||||
|
||||
public ShardMethodEnum getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public boolean hasContent() {
|
||||
return hasContent;
|
||||
}
|
||||
|
||||
public String toSpec() {
|
||||
StringBuilder spec = new StringBuilder(this.method.toString());
|
||||
if (this.hasContent)
|
||||
spec.append(";fulltext");
|
||||
for (Entry<String, String> c : this.config.entrySet()) {
|
||||
if (!c.getKey().startsWith("shard."))
|
||||
continue;
|
||||
spec.append(';').append(c.getKey().substring(6)).append(':').append(c.getValue());
|
||||
}
|
||||
return spec.toString();
|
||||
}
|
||||
|
||||
public Map<String, String> getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public boolean isFor(ShardState shardState) {
|
||||
return this.method.equals(shardState.getShardInstance().getShard().getFloc().getShardMethod()) &&
|
||||
this.hasContent == shardState.getShardInstance().getShard().getFloc().hasContent() &&
|
||||
this.isConfigurationFor(shardState.getPropertyBag());
|
||||
}
|
||||
|
||||
public boolean isConfigurationFor(Map<String, String> propertyBag) {
|
||||
for (Entry<String, String> config : this.config.entrySet()) {
|
||||
if (config.getValue() == null || !config.getValue().equals(propertyBag.get(config.getKey())))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof ShardSet))
|
||||
return false;
|
||||
|
||||
ShardSet shardSet = (ShardSet) obj;
|
||||
return this.method.equals(shardSet.method) && this.config.equals(shardSet.config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
if (this.hash == null) {
|
||||
this.hash = new HashCodeBuilder().append(this.method).append(this.hasContent).append(this.config).build();
|
||||
}
|
||||
|
||||
return this.hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.toSpec();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,129 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.time.Month;
|
||||
import java.time.Year;
|
||||
import java.time.temporal.WeekFields;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.alfresco.repo.index.shard.ShardInstance;
|
||||
import org.alfresco.repo.index.shard.ShardRegistry;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import com.inteligr8.alfresco.asie.Constants;
|
||||
import com.inteligr8.alfresco.asie.api.CoreAdminApi;
|
||||
import com.inteligr8.alfresco.asie.compute.SolrShardEnumeratedHashTable;
|
||||
import com.inteligr8.alfresco.asie.compute.SolrShardHashTable;
|
||||
import com.inteligr8.alfresco.asie.compute.SolrShardNumericHashTable;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.ShardInfo;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.ShardSetInfo;
|
||||
import com.inteligr8.alfresco.asie.rest.AbstractAsieWebScript;
|
||||
import com.inteligr8.alfresco.asie.service.SolrShardHashService;
|
||||
|
||||
public abstract class AbstractAsieEnterpriseWebScript extends AbstractAsieWebScript {
|
||||
|
||||
private final Pattern sampleTypePattern = Pattern.compile("([A-Za-z]+)([0-9]+)");
|
||||
|
||||
public enum SolrShardHashSampleType {
|
||||
PropertyYear,
|
||||
PropertyQuarter,
|
||||
PropertyMonth,
|
||||
PropertyWeek
|
||||
}
|
||||
|
||||
@Autowired
|
||||
@Qualifier(Constants.BEAN_SHARD_REGISTRY)
|
||||
private ShardRegistry shardRegistry;
|
||||
|
||||
@Autowired
|
||||
private SolrShardHashService sshs;
|
||||
|
||||
protected ShardRegistry getShardRegistry() {
|
||||
return shardRegistry;
|
||||
}
|
||||
|
||||
protected SolrShardHashTable<?> createSampleHashTable(String sampleType) {
|
||||
Matcher matcher = this.sampleTypePattern.matcher(sampleType);
|
||||
if (!matcher.find())
|
||||
throw new WebScriptException(HttpStatus.BAD_REQUEST.value(), "The 'sampleType` is not properly formatted");
|
||||
|
||||
try {
|
||||
SolrShardHashSampleType type = SolrShardHashSampleType.valueOf(matcher.group(1));
|
||||
int shards = Integer.parseInt(matcher.group(2));
|
||||
return this.createSampleHashTable(type, shards);
|
||||
} catch (NumberFormatException nfe) {
|
||||
// this should never happen, because of the regex
|
||||
throw new WebScriptException(HttpStatus.BAD_REQUEST.value(), "The 'sampleType` number '" + matcher.group(2) + "' is not properly formatted");
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new WebScriptException(HttpStatus.BAD_REQUEST.value(), "The 'sampleType` '" + matcher.group(1) + "' is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
protected SolrShardHashTable<?> createSampleHashTable(SolrShardHashSampleType sampleType, int shards) {
|
||||
int thisYear = Year.now().getValue();
|
||||
|
||||
switch (sampleType) {
|
||||
case PropertyYear:
|
||||
return new SolrShardNumericHashTable(shards, this.sshs).build(thisYear-40, thisYear+10);
|
||||
case PropertyQuarter:
|
||||
List<String> quarters = new LinkedList<>();
|
||||
for (int year = thisYear - 15; year <= thisYear + 5; year++)
|
||||
for (int quarter = 1; quarter <= 4; quarter++)
|
||||
quarters.add(year + "-Q" + quarter);
|
||||
return new SolrShardEnumeratedHashTable(shards, this.sshs).build(quarters);
|
||||
case PropertyMonth:
|
||||
NumberFormat monthFormat = NumberFormat.getInstance();
|
||||
monthFormat.setMinimumIntegerDigits(2);
|
||||
|
||||
List<String> months = new LinkedList<>();
|
||||
for (int year = thisYear - 15; year <= thisYear + 5; year++)
|
||||
for (Month month : Month.values())
|
||||
months.add(year + "-" + monthFormat.format(month.getValue()));
|
||||
return new SolrShardEnumeratedHashTable(shards, this.sshs).build(months);
|
||||
case PropertyWeek:
|
||||
List<String> weeks = new LinkedList<>();
|
||||
for (int year = thisYear - 15; year <= thisYear + 5; year++) {
|
||||
int maxWeek = LocalDate.of(year, Month.DECEMBER.getValue(), 31).get(WeekFields.SUNDAY_START.weekOfYear());
|
||||
for (int week = 1; week <= maxWeek; week++)
|
||||
weeks.add(year + "-W" + week);
|
||||
}
|
||||
return new SolrShardEnumeratedHashTable(shards, this.sshs).build(weeks);
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
protected void addShardHashSamples(ShardSetInfo shardSet, ShardInfo shard, SolrShardHashTable<?> sampleHashTable) {
|
||||
Set<Object> existingValues = shardSet.getShardHashSamples().get(shard.getId());
|
||||
if (existingValues == null) {
|
||||
existingValues = new HashSet<>();
|
||||
shardSet.getShardHashSamples().put(shard.getId(), existingValues);
|
||||
}
|
||||
|
||||
Set<?> values = sampleHashTable.hashReverse(shard.getId());
|
||||
if (values != null)
|
||||
existingValues.addAll(values);
|
||||
}
|
||||
|
||||
protected void addShardHashSamples(ShardInfo shard, SolrShardHashTable<?> sampleHashTable) {
|
||||
this.addShardHashSamples(shard.getShardSet(), shard, sampleHashTable);
|
||||
}
|
||||
|
||||
protected int getLatestTxId() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected CoreAdminApi getApi(ShardInstance shard) {
|
||||
return this.createApi(shard.getHostName(), shard.getPort());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
|
||||
import com.inteligr8.alfresco.asie.enterprise.model.ShardSet;
|
||||
|
||||
public abstract class AbstractAsieNodeShardWebScript extends AbstractAsieEnterpriseWebScript {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Override
|
||||
public final void executeAuthorized(WebScriptRequest req, WebScriptResponse res) throws IOException {
|
||||
this.logger.trace("execute()");
|
||||
|
||||
String nodeEndpoint = this.getRequiredPathParameter(req, "nodeEndpoint");
|
||||
int colon = nodeEndpoint.lastIndexOf(':');
|
||||
String nodeHostname = colon < 0 ? nodeEndpoint : nodeEndpoint.substring(0, colon);
|
||||
int nodePort = colon < 0 ? this.getDefaultSolrPort() : Integer.parseInt(nodeEndpoint.substring(colon+1));
|
||||
|
||||
ShardSet shardSet = this.getRequiredPathParameter(req, "shardSet", ShardSet.class);
|
||||
int shardId = this.getRequiredPathParameter(req, "shardId", Integer.class);
|
||||
|
||||
this.execute(req, res, nodeHostname, nodePort, shardSet, shardId);
|
||||
}
|
||||
|
||||
protected abstract void execute(WebScriptRequest req, WebScriptResponse res,
|
||||
String nodeHostname, int nodePort, ShardSet shardSet, int shardId)
|
||||
throws IOException;
|
||||
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.index.shard.ShardState;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import com.inteligr8.alfresco.asie.enterprise.service.ShardDiscoveryService;
|
||||
|
||||
public abstract class AbstractAsieNodeWebScript extends AbstractAsieEnterpriseWebScript {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Autowired
|
||||
private ShardDiscoveryService sds;
|
||||
|
||||
@Override
|
||||
public final void executeAuthorized(WebScriptRequest req, WebScriptResponse res) throws IOException {
|
||||
this.logger.trace("execute()");
|
||||
|
||||
String nodeEndpoint = this.getRequiredPathParameter(req, "nodeEndpoint");
|
||||
int colon = nodeEndpoint.lastIndexOf(':');
|
||||
String nodeHostname = colon < 0 ? nodeEndpoint : nodeEndpoint.substring(0, colon);
|
||||
nodeHostname = nodeHostname.replace('_', '.');
|
||||
int nodePort = colon < 0 ? this.getDefaultSolrPort() : Integer.parseInt(nodeEndpoint.substring(colon+1));
|
||||
|
||||
this.execute(req, res, nodeHostname, nodePort);
|
||||
}
|
||||
|
||||
protected void execute(WebScriptRequest req, WebScriptResponse res, String nodeHostname, int nodePort) throws IOException {
|
||||
this.logger.trace("execute({}, {})", nodeHostname, nodePort);
|
||||
|
||||
Set<ShardState> shardsOnNode = this.sds.findByNode(nodeHostname, nodePort);
|
||||
if (shardsOnNode == null || shardsOnNode.isEmpty())
|
||||
throw new WebScriptException(HttpStatus.NOT_FOUND.value(), "The ASIE node could not be found");
|
||||
|
||||
this.execute(req, res, shardsOnNode);
|
||||
}
|
||||
|
||||
protected void execute(WebScriptRequest req, WebScriptResponse res, Set<ShardState> registeredNodeShards) throws IOException {
|
||||
this.logger.trace("execute({})", registeredNodeShards.size());
|
||||
// made to be optionally overridden
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.index.shard.ShardState;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import com.inteligr8.alfresco.asie.enterprise.model.ShardSet;
|
||||
import com.inteligr8.alfresco.asie.enterprise.service.ShardDiscoveryService;
|
||||
|
||||
public abstract class AbstractAsieShardWebScript extends AbstractAsieEnterpriseWebScript {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Autowired
|
||||
private ShardDiscoveryService sds;
|
||||
|
||||
@Override
|
||||
public void executeAuthorized(WebScriptRequest req, WebScriptResponse res) throws IOException {
|
||||
this.logger.trace("execute()");
|
||||
|
||||
ShardSet shardSet = this.getRequiredPathParameter(req, "shardSet", ShardSet.class);
|
||||
this.logger.debug("Parsed shard set: {}", shardSet);
|
||||
int shardId = this.getRequiredPathParameter(req, "shardId", Integer.class);
|
||||
|
||||
try {
|
||||
Set<ShardState> registeredShardNodes = this.sds.findByShard(shardSet, shardId);
|
||||
if (registeredShardNodes == null || registeredShardNodes.isEmpty())
|
||||
throw new WebScriptException(HttpStatus.NOT_FOUND.value(), "The ASIE shard set or shard could not be found");
|
||||
|
||||
this.execute(req, res, registeredShardNodes);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new WebScriptException(HttpStatus.BAD_REQUEST.value(), iae.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void execute(WebScriptRequest req, WebScriptResponse res, Set<ShardState> registeredShardNodes) throws IOException;
|
||||
|
||||
}
|
@@ -0,0 +1,164 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.alfresco.repo.index.shard.ShardState;
|
||||
import org.alfresco.service.cmr.attributes.AttributeService;
|
||||
import org.alfresco.service.cmr.attributes.AttributeService.AttributeQueryCallback;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import com.inteligr8.alfresco.asie.Constants;
|
||||
import com.inteligr8.alfresco.asie.api.CoreAdminApi;
|
||||
import com.inteligr8.alfresco.asie.enterprise.service.ShardBackupService;
|
||||
import com.inteligr8.alfresco.asie.enterprise.service.ShardStateService;
|
||||
import com.inteligr8.alfresco.asie.model.NodeParameterSet;
|
||||
import com.inteligr8.alfresco.asie.model.core.DisableIndexingRequest;
|
||||
import com.inteligr8.solr.model.CoreMetadata;
|
||||
import com.inteligr8.solr.model.core.StatusRequest;
|
||||
import com.inteligr8.solr.model.core.StatusResponse;
|
||||
import com.inteligr8.solr.model.core.UnloadRequest;
|
||||
|
||||
public abstract class AbstractUnregisterNodeWebScript<T extends NodeParameterSet> extends AbstractAsieNodeWebScript {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Autowired
|
||||
@Qualifier(Constants.QUALIFIER_ASIE)
|
||||
private AttributeService attrService;
|
||||
|
||||
@Autowired
|
||||
private ShardBackupService sbs;
|
||||
|
||||
@Autowired
|
||||
private ShardStateService sss;
|
||||
|
||||
protected abstract T createParameters(WebScriptRequest req, String nodeHostname, int nodePort);
|
||||
|
||||
@Override
|
||||
protected void execute(WebScriptRequest req, WebScriptResponse res, String nodeHostname, int nodePort)
|
||||
throws IOException {
|
||||
T params = this.createParameters(req, nodeHostname, nodePort);
|
||||
|
||||
final Map<String, ShardState> guidCores = new HashMap<>();
|
||||
|
||||
AttributeQueryCallback callback = new AttributeQueryCallback() {
|
||||
@Override
|
||||
public boolean handleAttribute(Long id, Serializable value, Serializable[] keys) {
|
||||
ShardState shardState = (ShardState) value;
|
||||
if (!matches(params, shardState))
|
||||
return true;
|
||||
|
||||
String guid = (String) keys[1];
|
||||
guidCores.put(guid, shardState);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
this.attrService.getAttributes(callback, Constants.ATTR_SHARD_STATE);
|
||||
|
||||
Serializable[] keys = new String[] {
|
||||
Constants.ATTR_ASIE,
|
||||
Constants.ATTR_UNLOADED_NODE_CORES,
|
||||
nodeHostname + ":" + nodePort
|
||||
};
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, String> cores = (Map<String, String>) this.attrService.getAttribute(keys);
|
||||
if (cores == null)
|
||||
cores = new HashMap<>();
|
||||
try {
|
||||
for (Entry<String, ShardState> guidCore : guidCores.entrySet()) {
|
||||
ShardState shardNode = guidCore.getValue();
|
||||
String core = shardNode.getPropertyBag().get("coreName");
|
||||
|
||||
StatusResponse status = this.getCoreStatus(nodeHostname, nodePort, core);
|
||||
if (status == null)
|
||||
throw new WebScriptException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "This should never happen");
|
||||
CoreMetadata coreMetadata = status.getStatus().getCores().get(core);
|
||||
if (coreMetadata == null || coreMetadata.getName() == null) {
|
||||
this.logger.warn("Registered core does not actually exist on the node host; could be a DNS issue: {}:{}/solr/{}", nodeHostname, nodePort, core);
|
||||
continue;
|
||||
}
|
||||
|
||||
this.unloadCore(nodeHostname, nodePort, core);
|
||||
cores.put(core, coreMetadata.getInstancePath());
|
||||
|
||||
String guid = guidCore.getKey();
|
||||
this.removeShard(guid, shardNode);
|
||||
}
|
||||
} finally {
|
||||
// FIXME maybe a separate tx?
|
||||
this.attrService.setAttribute((Serializable) cores, keys);
|
||||
}
|
||||
|
||||
res.setStatus(HttpStatus.OK.value());
|
||||
}
|
||||
|
||||
protected boolean matches(T params, ShardState shardState) {
|
||||
if (!params.getHostname().equalsIgnoreCase(shardState.getShardInstance().getHostName())) {
|
||||
InetAddress nodeAddress = params.getAddress();
|
||||
if (nodeAddress == null)
|
||||
return false;
|
||||
InetAddress shardNodeAddress = resolve(shardState.getShardInstance().getHostName());
|
||||
if (!nodeAddress.equals(shardNodeAddress))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (params.getPort() != shardState.getShardInstance().getPort())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private InetAddress resolve(String hostname) {
|
||||
try {
|
||||
return InetAddress.getByName(hostname);
|
||||
} catch (UnknownHostException uhe) {
|
||||
// suppress
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected StatusResponse getCoreStatus(String nodeHostname, int nodePort, String core) {
|
||||
this.logger.debug("Retrieving status for core {} on ASIE node: {}", core, nodeHostname);
|
||||
CoreAdminApi api = this.createApi(nodeHostname, nodePort);
|
||||
return api.getStatus(new StatusRequest().withCore(core));
|
||||
}
|
||||
|
||||
protected void unloadCore(String nodeHostname, int nodePort, String core) {
|
||||
this.logger.info("Unloading core {} on ASIE node: {}", core, nodeHostname);
|
||||
CoreAdminApi api = this.createApi(nodeHostname, nodePort);
|
||||
api.unload(new UnloadRequest().withCore(core));
|
||||
}
|
||||
|
||||
protected void disableIndexing(String nodeHostname, int nodePort) {
|
||||
this.logger.info("Disabling indexing on ASIE node: {}", nodeHostname);
|
||||
CoreAdminApi api = this.createApi(nodeHostname, nodePort);
|
||||
api.disableIndexing(new DisableIndexingRequest());
|
||||
}
|
||||
|
||||
protected void disableCoreIndexing(String nodeHostname, int nodePort, String core) {
|
||||
this.logger.info("Disabling indexing on ASIE node/core: {}/{}", nodeHostname, core);
|
||||
CoreAdminApi api = this.createApi(nodeHostname, nodePort);
|
||||
api.disableIndexing(new DisableIndexingRequest().withCore(core));
|
||||
}
|
||||
|
||||
protected void removeShard(String guid, ShardState shardNode) {
|
||||
this.sss.clear(guid);
|
||||
this.sbs.forget(shardNode);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.extensions.webscripts.AbstractWebScript;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.inteligr8.alfresco.asie.enterprise.service.ShardBackupService;
|
||||
import com.inteligr8.alfresco.asie.enterprise.service.ShardStateService;
|
||||
|
||||
@Component(value = "webscript.com.inteligr8.alfresco.asie.enterprise.registry.delete")
|
||||
public class ClearRegistryWebScript extends AbstractWebScript {
|
||||
|
||||
@Autowired
|
||||
private ShardBackupService sbs;
|
||||
|
||||
@Autowired
|
||||
private ShardStateService sss;
|
||||
|
||||
@Override
|
||||
public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException {
|
||||
this.sss.clear();
|
||||
this.sbs.forget();
|
||||
|
||||
res.setStatus(HttpStatus.OK.value());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.index.shard.ShardState;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.inteligr8.alfresco.asie.enterprise.service.ShardBackupService;
|
||||
|
||||
@Component(value = "webscript.com.inteligr8.alfresco.asie.enterprise.backupNode.get")
|
||||
public class GetBackupNodeWebScript extends AbstractAsieShardWebScript {
|
||||
|
||||
@Autowired
|
||||
private ShardBackupService sbs;
|
||||
|
||||
@Override
|
||||
public void execute(WebScriptRequest req, WebScriptResponse res, Set<ShardState> shardNodes) throws IOException {
|
||||
if (shardNodes.isEmpty())
|
||||
throw new WebScriptException(HttpStatus.NOT_FOUND.value(), "The ASIE shard state could not be found");
|
||||
|
||||
String nodeId = this.sbs.fetchNodeId(shardNodes);
|
||||
|
||||
res.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
res.setContentEncoding("utf-8");
|
||||
this.getObjectMapper().writeValue(res.getWriter(), nodeId);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.index.shard.ShardInstance;
|
||||
import org.alfresco.repo.index.shard.ShardState;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.NodeInfo;
|
||||
import com.inteligr8.alfresco.asie.enterprise.service.ShardAnalysisService;
|
||||
|
||||
@Component(value = "webscript.com.inteligr8.alfresco.asie.enterprise.leadNode.get")
|
||||
public class GetLeadNodeWebScript extends AbstractAsieShardWebScript {
|
||||
|
||||
@Autowired
|
||||
private ShardAnalysisService sas;
|
||||
|
||||
@Override
|
||||
public void execute(WebScriptRequest req, WebScriptResponse res, Set<ShardState> shardNodesCache) throws IOException {
|
||||
if (shardNodesCache.isEmpty())
|
||||
throw new WebScriptException(HttpStatus.NOT_FOUND.value(), "The ASIE shard state could not be found");
|
||||
|
||||
ShardInstance latestNode = this.sas.computeLeadShard(shardNodesCache);
|
||||
if (latestNode == null)
|
||||
throw new WebScriptException(HttpStatus.NOT_FOUND.value(), "The ASIE shard state could not be found");
|
||||
|
||||
res.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
res.setContentEncoding("utf-8");
|
||||
this.getObjectMapper().writeValue(res.getWriter(), NodeInfo.determineId(latestNode));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.index.shard.ShardInstance;
|
||||
import org.alfresco.repo.index.shard.ShardState;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.inteligr8.alfresco.asie.compute.SolrShardHashTable;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.NodeInfo;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.NodeShardInfo;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.ShardInfo;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.ShardSetInfo;
|
||||
|
||||
@Component(value = "webscript.com.inteligr8.alfresco.asie.enterprise.node.get")
|
||||
public class GetNodeWebScript extends AbstractAsieNodeWebScript {
|
||||
|
||||
@Override
|
||||
protected void execute(WebScriptRequest req, WebScriptResponse res, Set<ShardState> registeredNodeShards) throws IOException {
|
||||
ShardState anyRegisteredNodeShard = registeredNodeShards.iterator().next();
|
||||
ShardInstance registeredNode = anyRegisteredNodeShard.getShardInstance();
|
||||
int maxShards = registeredNode.getShard().getFloc().getNumberOfShards();
|
||||
|
||||
SolrShardHashSampleType sampleHashType = this.getOptionalQueryParameter(req, "sampleHashType", SolrShardHashSampleType.class);
|
||||
SolrShardHashTable<?> sampleHashTable = sampleHashType == null ? null : this.createSampleHashTable(sampleHashType, maxShards);
|
||||
|
||||
NodeInfo node = new NodeShardInfo(registeredNode);
|
||||
|
||||
for (ShardState registeredNodeShard : registeredNodeShards) {
|
||||
ShardInfo shard = new ShardInfo();
|
||||
shard.setId(registeredNodeShard.getShardInstance().getShard().getInstance());
|
||||
shard.setLatestTx(OffsetDateTime.ofInstant(Instant.ofEpochMilli(registeredNodeShard.getLastIndexedTxCommitTime()), ZoneOffset.UTC));
|
||||
shard.setTxsCompleted(registeredNodeShard.getLastIndexedTxId());
|
||||
|
||||
shard.setShardSet(new ShardSetInfo(registeredNodeShard.getShardInstance().getShard().getFloc(), registeredNodeShard));
|
||||
if (sampleHashTable != null)
|
||||
this.addShardHashSamples(shard, sampleHashTable);
|
||||
|
||||
node.getShards().put(shard.getId(), shard);
|
||||
}
|
||||
|
||||
res.setContentType("application/json");
|
||||
res.setContentEncoding("utf-8");
|
||||
this.getObjectMapper().writeValue(res.getWriter(), node);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,70 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.alfresco.repo.index.shard.Floc;
|
||||
import org.alfresco.repo.index.shard.Shard;
|
||||
import org.alfresco.repo.index.shard.ShardState;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.inteligr8.alfresco.asie.compute.SolrShardHashTable;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.NodeInfo;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.NodeShardInfo;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.ShardInfo;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.ShardSetInfo;
|
||||
|
||||
@Component(value = "webscript.com.inteligr8.alfresco.asie.enterprise.nodes.get")
|
||||
public class GetNodesWebScript extends AbstractAsieEnterpriseWebScript {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Override
|
||||
public void executeAuthorized(WebScriptRequest req, WebScriptResponse res) throws IOException {
|
||||
this.logger.trace("execute()");
|
||||
|
||||
Map<Floc, Map<Shard, Set<ShardState>>> flocs = this.getShardRegistry().getFlocs();
|
||||
if (flocs.isEmpty())
|
||||
throw new WebScriptException(HttpStatus.NO_CONTENT.value(), "There are no ASIE shards registred with ACS");
|
||||
|
||||
SolrShardHashSampleType sampleHashType = this.getOptionalQueryParameter(req, "sampleHashType", SolrShardHashSampleType.class);
|
||||
|
||||
Map<String, NodeInfo> nodes = new TreeMap<>();
|
||||
|
||||
for (Entry<Floc, Map<Shard, Set<ShardState>>> floc : flocs.entrySet()) {
|
||||
int maxShards = floc.getKey().getNumberOfShards();
|
||||
|
||||
SolrShardHashTable<?> sampleHashTable = sampleHashType == null ? null : this.createSampleHashTable(sampleHashType, maxShards);
|
||||
|
||||
for (Entry<Shard, Set<ShardState>> registeredShards : floc.getValue().entrySet()) {
|
||||
for (ShardState registeredShardNode : registeredShards.getValue()) {
|
||||
NodeInfo node = nodes.get(NodeInfo.determineId(registeredShardNode.getShardInstance()));
|
||||
if (node == null) {
|
||||
node = new NodeShardInfo(registeredShardNode.getShardInstance());
|
||||
nodes.put(node.getId(), node);
|
||||
}
|
||||
|
||||
ShardInfo shard = new ShardInfo(registeredShardNode);
|
||||
shard.setShardSet(new ShardSetInfo(floc.getKey(), registeredShardNode));
|
||||
if (sampleHashTable != null)
|
||||
this.addShardHashSamples(shard, sampleHashTable);
|
||||
node.getShards().put(shard.getId(), shard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res.setContentType("application/json");
|
||||
res.setContentEncoding("utf-8");
|
||||
this.getObjectMapper().writeValue(res.getWriter(), nodes);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,150 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.alfresco.repo.index.shard.Floc;
|
||||
import org.alfresco.repo.index.shard.Shard;
|
||||
import org.alfresco.repo.index.shard.ShardMethodEnum;
|
||||
import org.alfresco.repo.index.shard.ShardState;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.inteligr8.alfresco.asie.compute.SolrShardHashTable;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.NodeInfo;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.PropertyHashShardSetInfo;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.ShardInfo;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.ShardNodeInfo;
|
||||
import com.inteligr8.alfresco.asie.enterprise.service.ShardDiscoveryService;
|
||||
|
||||
@Component(value = "webscript.com.inteligr8.alfresco.asie.enterprise.propertyHashShards.get")
|
||||
public class GetPropertyHashShardsWebScript extends AbstractAsieEnterpriseWebScript {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Autowired
|
||||
private ShardDiscoveryService sds;
|
||||
|
||||
@Override
|
||||
public void executeAuthorized(WebScriptRequest req, WebScriptResponse res) throws IOException {
|
||||
this.logger.trace("execute()");
|
||||
|
||||
SolrShardHashSampleType sampleHashType = this.getRequiredPathParameter(req, "sampleHashType", SolrShardHashSampleType.class);
|
||||
|
||||
Integer max = this.getOptionalQueryParameter(req, "max", Integer.class);
|
||||
Integer min = this.getOptionalQueryParameter(req, "min", Integer.class);
|
||||
List<String> values = this.getOptionalQueryParameterAsList(req);
|
||||
this.validateParameters(min, max, values);
|
||||
|
||||
List<PropertyHashShardSetInfo> shardSets = new LinkedList<>();
|
||||
|
||||
Collection<Pair<Floc, Map<Shard, Set<ShardState>>>> flocs = this.sds.findByShardMethod(ShardMethodEnum.PROPERTY);
|
||||
if (flocs.isEmpty())
|
||||
throw new WebScriptException(HttpStatus.NO_CONTENT.value(), "There are no property-based shards");
|
||||
|
||||
for (Pair<Floc, Map<Shard, Set<ShardState>>> floc : flocs) {
|
||||
ShardState anyShardNode = this.getAnyShardNode(floc.getSecond());
|
||||
PropertyHashShardSetInfo shardSet = new PropertyHashShardSetInfo(floc.getFirst(), anyShardNode);
|
||||
shardSet.setShards(new TreeMap<>());
|
||||
|
||||
int maxShards = floc.getFirst().getNumberOfShards();
|
||||
SolrShardHashTable<?> sampleHashTable = this.createSampleHashTable(sampleHashType, maxShards);
|
||||
|
||||
Map<Integer, List<Object>> shardToHashMap = new HashMap<>();
|
||||
|
||||
if (max != null && min != null) {
|
||||
for (int i = min; i <= max; i++) {
|
||||
int shardId = sampleHashTable.hashForward(i);
|
||||
this.getAdd(shardToHashMap, shardId, i);
|
||||
}
|
||||
} else if (values != null) {
|
||||
for (String value : values) {
|
||||
int shardId = sampleHashTable.hashForward(value);
|
||||
this.getAdd(shardToHashMap, shardId, value);
|
||||
}
|
||||
}
|
||||
|
||||
for (Entry<Shard, Set<ShardState>> shardCache : floc.getSecond().entrySet()) {
|
||||
ShardInfo shard = new ShardInfo();
|
||||
shard.setId(shardCache.getKey().getInstance());
|
||||
shard.setNodes(new HashMap<>());
|
||||
|
||||
for (ShardState shardNodeCache : shardCache.getValue()) {
|
||||
if (shard.getTxsCompleted() == null || shard.getTxsCompleted().longValue() < shardNodeCache.getLastIndexedTxId()) {
|
||||
shard.setLatestTx(OffsetDateTime.ofInstant(Instant.ofEpochMilli(shardNodeCache.getLastIndexedTxCommitTime()), ZoneOffset.UTC));
|
||||
shard.setTxsCompleted(shardNodeCache.getLastIndexedTxId());
|
||||
}
|
||||
|
||||
NodeInfo node = new ShardNodeInfo(shardNodeCache);
|
||||
shard.getNodes().put(node.getId(), node);
|
||||
}
|
||||
|
||||
List<Object> hashedValues = shardToHashMap.get(shard.getId());
|
||||
if (hashedValues != null) for (Object hashedValue : hashedValues)
|
||||
shardSet.getShards().put(hashedValue, shard);
|
||||
}
|
||||
|
||||
shardSets.add(shardSet);
|
||||
}
|
||||
|
||||
res.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
res.setContentEncoding("utf-8");
|
||||
this.getObjectMapper().writeValue(res.getWriter(), shardSets);
|
||||
}
|
||||
|
||||
private ShardState getAnyShardNode(Map<Shard, Set<ShardState>> shards) {
|
||||
for (Set<ShardState> shardNodes : shards.values())
|
||||
for (ShardState shardNode : shardNodes)
|
||||
return shardNode;
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<String> getOptionalQueryParameterAsList(WebScriptRequest req) {
|
||||
String valuesStr = this.getOptionalQueryParameter(req, "values");
|
||||
if (valuesStr == null)
|
||||
return null;
|
||||
|
||||
String[] values = valuesStr.trim().split("[ ]*[,|][ ]*");
|
||||
return Arrays.asList(values);
|
||||
}
|
||||
|
||||
private void validateParameters(Integer min, Integer max, List<String> values) {
|
||||
if (max != null && min != null) {
|
||||
if (min > max)
|
||||
throw new WebScriptException(HttpStatus.BAD_REQUEST.value(), "The `min` parameter value may not be greater than the `max` parameter value");
|
||||
} else if (values != null) {
|
||||
} else {
|
||||
throw new WebScriptException(HttpStatus.BAD_REQUEST.value(), "Either `min`/`max` or `values` query parameter is required");
|
||||
}
|
||||
}
|
||||
|
||||
private <K, V> void getAdd(Map<K, List<V>> map, K key, V value) {
|
||||
List<V> values = map.get(key);
|
||||
if (values == null) {
|
||||
values = new LinkedList<>();
|
||||
map.put(key, values);
|
||||
}
|
||||
|
||||
values.add(value);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,96 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.inteligr8.alfresco.asie.compute.SolrShardEnumeratedHashTable;
|
||||
import com.inteligr8.alfresco.asie.compute.SolrShardHashTable;
|
||||
import com.inteligr8.alfresco.asie.compute.SolrShardNumericHashTable;
|
||||
import com.inteligr8.alfresco.asie.service.SolrShardHashService;
|
||||
|
||||
@Component(value = "webscript.com.inteligr8.alfresco.asie.enterprise.sampleHashes.get")
|
||||
public class GetSampleHashesWebScript extends AbstractAsieEnterpriseWebScript {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Autowired
|
||||
private SolrShardHashService sshs;
|
||||
|
||||
@Override
|
||||
public void executeAuthorized(WebScriptRequest req, WebScriptResponse res) throws IOException {
|
||||
this.logger.trace("execute()");
|
||||
|
||||
int shards = this.getRequiredPathParameter(req, "shards", Integer.class);
|
||||
Integer max = this.getOptionalQueryParameter(req, "max", Integer.class);
|
||||
Integer min = this.getOptionalQueryParameter(req, "min", Integer.class);
|
||||
List<String> values = this.getOptionalQueryParameterAsList(req);
|
||||
this.validateParameters(min, max, values);
|
||||
|
||||
Map<String, Integer> forward = new HashMap<>();
|
||||
Map<Integer, Collection<? extends Object>> reverse = new HashMap<>();
|
||||
|
||||
SolrShardHashTable<?> table = null;
|
||||
if (max != null && min != null) {
|
||||
table = new SolrShardNumericHashTable(shards, this.sshs).build(min, max);
|
||||
for (int i = min; i <= max; i++)
|
||||
forward.put(String.valueOf(i), table.hashForward(i));
|
||||
} else if (values != null) {
|
||||
table = new SolrShardEnumeratedHashTable(shards, this.sshs).build(values);
|
||||
for (String value : values)
|
||||
forward.put(value, table.hashForward(value));
|
||||
}
|
||||
|
||||
for (int s = 0; s < shards; s++) {
|
||||
Set<?> vs = table.hashReverse(s);
|
||||
if (vs != null && !vs.isEmpty()) {
|
||||
reverse.put(s, vs);
|
||||
} else {
|
||||
reverse.put(s, Collections.emptyList());
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Map<?, ?>> response = new HashMap<>();
|
||||
response.put("forward", forward);
|
||||
response.put("reverse", reverse);
|
||||
|
||||
res.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
res.setContentEncoding("utf-8");
|
||||
this.getObjectMapper().writeValue(res.getWriter(), response);
|
||||
}
|
||||
|
||||
private List<String> getOptionalQueryParameterAsList(WebScriptRequest req) {
|
||||
String valuesStr = this.getOptionalQueryParameter(req, "values");
|
||||
if (valuesStr == null)
|
||||
return null;
|
||||
|
||||
String[] values = valuesStr.trim().split("[ ]*[,|][ ]*");
|
||||
return Arrays.asList(values);
|
||||
}
|
||||
|
||||
private void validateParameters(Integer min, Integer max, List<String> values) {
|
||||
if (max != null && min != null) {
|
||||
if (min > max)
|
||||
throw new WebScriptException(HttpStatus.BAD_REQUEST.value(), "The `min` parameter value may not be greater than the `max` parameter value");
|
||||
} else if (values != null) {
|
||||
} else {
|
||||
throw new WebScriptException(HttpStatus.BAD_REQUEST.value(), "Either `min`/`max` or `values` query parameter is required");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.alfresco.repo.index.shard.Shard;
|
||||
import org.alfresco.repo.index.shard.ShardState;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.inteligr8.alfresco.asie.compute.SolrShardHashTable;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.NodeInfo;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.ShardInfo;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.ShardNodeInfo;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.ShardSetInfo;
|
||||
|
||||
@Component(value = "webscript.com.inteligr8.alfresco.asie.enterprise.shard.get")
|
||||
public class GetShardWebScript extends AbstractAsieShardWebScript {
|
||||
|
||||
@Override
|
||||
public void execute(WebScriptRequest req, WebScriptResponse res, Set<ShardState> registeredShardNodes) throws IOException {
|
||||
ShardState aRegisteredShardNode = registeredShardNodes.iterator().next();
|
||||
Shard registeredShard = aRegisteredShardNode.getShardInstance().getShard();
|
||||
int maxShards = registeredShard.getFloc().getNumberOfShards();
|
||||
|
||||
SolrShardHashSampleType sampleHashType = this.getOptionalQueryParameter(req, "sampleHashType", SolrShardHashSampleType.class);
|
||||
SolrShardHashTable<?> sampleHashTable = sampleHashType == null ? null : this.createSampleHashTable(sampleHashType, maxShards);
|
||||
|
||||
ShardInfo shard = new ShardInfo();
|
||||
shard.setId(registeredShard.getInstance());
|
||||
shard.setShardSet(new ShardSetInfo(registeredShard.getFloc(), aRegisteredShardNode));
|
||||
shard.setNodes(new TreeMap<>());
|
||||
if (sampleHashTable != null)
|
||||
this.addShardHashSamples(shard, sampleHashTable);
|
||||
|
||||
for (ShardState registeredShardNode : registeredShardNodes) {
|
||||
if (shard.getTxsCompleted() == null || shard.getTxsCompleted().longValue() < registeredShardNode.getLastIndexedTxId()) {
|
||||
shard.setLatestTx(OffsetDateTime.ofInstant(Instant.ofEpochMilli(registeredShardNode.getLastIndexedTxCommitTime()), ZoneOffset.UTC));
|
||||
shard.setTxsCompleted(registeredShardNode.getLastIndexedTxId());
|
||||
}
|
||||
|
||||
NodeInfo node = new ShardNodeInfo(registeredShardNode);
|
||||
shard.getNodes().put(node.getId(), node);
|
||||
}
|
||||
|
||||
res.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
res.setContentEncoding("utf-8");
|
||||
this.getObjectMapper().writeValue(res.getWriter(), shard);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,90 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.alfresco.repo.index.shard.Floc;
|
||||
import org.alfresco.repo.index.shard.Shard;
|
||||
import org.alfresco.repo.index.shard.ShardState;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.inteligr8.alfresco.asie.compute.SolrShardHashTable;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.NodeInfo;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.ShardInfo;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.ShardNodeInfo;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.ShardSetInfo;
|
||||
|
||||
@Component(value = "webscript.com.inteligr8.alfresco.asie.enterprise.shards.get")
|
||||
public class GetShardsWebScript extends AbstractAsieEnterpriseWebScript {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Override
|
||||
public void executeAuthorized(WebScriptRequest req, WebScriptResponse res) throws IOException {
|
||||
this.logger.trace("execute()");
|
||||
|
||||
Map<Floc, Map<Shard, Set<ShardState>>> flocs = this.getShardRegistry().getFlocs();
|
||||
if (flocs.isEmpty())
|
||||
throw new WebScriptException(HttpStatus.NO_CONTENT.value(), "There are no ASIE shards registred with ACS");
|
||||
|
||||
SolrShardHashSampleType sampleHashType = this.getOptionalQueryParameter(req, "sampleHashType", SolrShardHashSampleType.class);
|
||||
|
||||
Map<String, ShardSetInfo> shardSets = new TreeMap<>();
|
||||
|
||||
for (Entry<Floc, Map<Shard, Set<ShardState>>> floc : flocs.entrySet()) {
|
||||
int maxShards = floc.getKey().getNumberOfShards();
|
||||
ShardState anyShardNode = this.getAnyShardNode(floc.getValue());
|
||||
ShardSetInfo shardSet = new ShardSetInfo(floc.getKey(), anyShardNode);
|
||||
shardSet.setShards(new TreeMap<>());
|
||||
|
||||
SolrShardHashTable<?> sampleHashTable = sampleHashType == null ? null : this.createSampleHashTable(sampleHashType, maxShards);
|
||||
|
||||
for (Entry<Shard, Set<ShardState>> registeredShard : floc.getValue().entrySet()) {
|
||||
ShardInfo shard = new ShardInfo();
|
||||
shard.setId(registeredShard.getKey().getInstance());
|
||||
shard.setNodes(new TreeMap<>());
|
||||
|
||||
for (ShardState registeredShardNode : registeredShard.getValue()) {
|
||||
if (shard.getTxsCompleted() == null || shard.getTxsCompleted().longValue() < registeredShardNode.getLastIndexedTxId()) {
|
||||
shard.setLatestTx(OffsetDateTime.ofInstant(Instant.ofEpochMilli(registeredShardNode.getLastIndexedTxCommitTime()), ZoneOffset.UTC));
|
||||
shard.setTxsCompleted(registeredShardNode.getLastIndexedTxId());
|
||||
}
|
||||
|
||||
NodeInfo node = new ShardNodeInfo(registeredShardNode);
|
||||
shard.getNodes().put(node.getId(), node);
|
||||
}
|
||||
|
||||
if (sampleHashTable != null)
|
||||
this.addShardHashSamples(shardSet, shard, sampleHashTable);
|
||||
shardSet.getShards().put(shard.getId(), shard);
|
||||
}
|
||||
|
||||
shardSets.put(shardSet.getMethodSpec(), shardSet);
|
||||
}
|
||||
|
||||
res.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
res.setContentEncoding("utf-8");
|
||||
this.getObjectMapper().writeValue(res.getWriter(), shardSets);
|
||||
}
|
||||
|
||||
private ShardState getAnyShardNode(Map<Shard, Set<ShardState>> shards) {
|
||||
for (Set<ShardState> shardNodes : shards.values())
|
||||
for (ShardState shardNode : shardNodes)
|
||||
return shardNode;
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,135 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.alfresco.service.cmr.attributes.AttributeService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.inteligr8.alfresco.asie.Constants;
|
||||
import com.inteligr8.alfresco.asie.api.CoreAdminApi;
|
||||
import com.inteligr8.solr.model.ExceptionResponse;
|
||||
import com.inteligr8.solr.model.core.CreateRequest;
|
||||
import com.inteligr8.solr.model.core.ReloadRequest;
|
||||
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
import jakarta.ws.rs.InternalServerErrorException;
|
||||
|
||||
@Component(value = "webscript.com.inteligr8.alfresco.asie.enterprise.nodeShard.post")
|
||||
public class ReloadNodeShardWebScript extends AbstractAsieNodeWebScript {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
private final Pattern shardRangePattern = Pattern.compile("([0-9]+)-([0-9]+)");
|
||||
|
||||
@Autowired
|
||||
@Qualifier(Constants.QUALIFIER_ASIE)
|
||||
private AttributeService attrService;
|
||||
|
||||
@Override
|
||||
protected void execute(WebScriptRequest req, WebScriptResponse res, final String nodeHostname, final int nodePort)
|
||||
throws IOException {
|
||||
String shardCore = this.getRequiredPathParameter(req, "shardCore");
|
||||
int shardId = this.getRequiredPathParameter(req, "shardId", Integer.class);
|
||||
String coreName = shardCore + "-" + shardId;
|
||||
|
||||
Serializable[] keys = new String[] {
|
||||
Constants.ATTR_ASIE,
|
||||
Constants.ATTR_UNLOADED_NODE_CORES,
|
||||
nodeHostname + ":" + nodePort
|
||||
};
|
||||
|
||||
Map<String, String> cores = this.fetchUnloadedCores(keys);
|
||||
if (!cores.containsKey(coreName)) {
|
||||
cores.putAll(this.fetchOtherCores(req));
|
||||
}
|
||||
|
||||
boolean changed = false;
|
||||
String coreInstancePath = cores.get(coreName);
|
||||
if (coreInstancePath == null)
|
||||
throw new WebScriptException(HttpStatus.NOT_FOUND.value(), "The specified node/shard could not be found or formulated");
|
||||
|
||||
this.logger.info("Reloading core {} on ASIE node: {}", coreName, nodeHostname);
|
||||
CoreAdminApi api = this.createApi(nodeHostname, nodePort);
|
||||
try {
|
||||
api.create(new CreateRequest()
|
||||
.withCore(coreName)
|
||||
.withConfigDirectory(coreInstancePath));
|
||||
} catch (BadRequestException bre) {
|
||||
this.logger.warn("Core {} does not exist on ASIE node: {}; forgetting it", coreName, nodeHostname);
|
||||
cores.remove(coreName);
|
||||
changed = true;
|
||||
} catch (InternalServerErrorException isee) {
|
||||
ExceptionResponse response = isee.getResponse().readEntity(ExceptionResponse.class);
|
||||
if (response.getError() == null || response.getError().getMessage() == null || !response.getError().getMessage().endsWith(" already exists."))
|
||||
throw isee;
|
||||
|
||||
this.logger.warn("Core {} was already loaded on ASIE node: {}; reloading ...", coreName, nodeHostname);
|
||||
api.reload(new ReloadRequest()
|
||||
.withCore(coreName));
|
||||
}
|
||||
|
||||
if (changed)
|
||||
this.attrService.setAttribute((Serializable) cores, keys);
|
||||
|
||||
res.setStatus(HttpStatus.OK.value());
|
||||
}
|
||||
|
||||
private Map<String, String> fetchUnloadedCores(Serializable[] keys) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, String> cores = (Map<String, String>) this.attrService.getAttribute(keys);
|
||||
if (cores == null)
|
||||
cores = new HashMap<String, String>();
|
||||
return cores;
|
||||
}
|
||||
|
||||
private Map<String, String> fetchOtherCores(WebScriptRequest req) {
|
||||
String coreName = this.getOptionalQueryParameter(req, "coreName");
|
||||
if (coreName == null)
|
||||
coreName = this.getOptionalQueryParameter(req, "core");
|
||||
String shardRange = this.getOptionalQueryParameter(req, "shardRange");
|
||||
Short shardCount = this.getOptionalQueryParameter(req, "shardCount", Short.class);
|
||||
if (coreName == null || shardRange == null || shardCount == null)
|
||||
return Collections.emptyMap();
|
||||
|
||||
String template = this.getOptionalQueryParameter(req, "template");
|
||||
if (template == null)
|
||||
template = "rerank";
|
||||
Short nodeId = this.getOptionalQueryParameter(req, "nodeId", Short.class);
|
||||
if (nodeId == null)
|
||||
nodeId = 1;
|
||||
Short nodeCount = this.getOptionalQueryParameter(req, "nodeCount", Short.class);
|
||||
if (nodeCount == null)
|
||||
nodeCount = 2;
|
||||
|
||||
String baseConfigDirectory = template + "--" + coreName + "--shards--" + shardCount + "-x-1--node--" + nodeId + "-of-" + nodeCount;
|
||||
|
||||
Matcher matcher = this.shardRangePattern.matcher(shardRange);
|
||||
if (!matcher.find())
|
||||
throw new WebScriptException(HttpStatus.BAD_REQUEST.value(), "The 'shardRange' query parameter value is not formatted as expected");
|
||||
|
||||
Map<String, String> cores = new HashMap<>();
|
||||
|
||||
short startShardId = Short.parseShort(matcher.group(1));
|
||||
short endShardId = Short.parseShort(matcher.group(2));
|
||||
for (short shardId = startShardId; shardId <= endShardId; shardId++) {
|
||||
String shardConfigDirectory = baseConfigDirectory + "/" + coreName + "-" + shardId;
|
||||
cores.put(coreName, shardConfigDirectory);
|
||||
}
|
||||
|
||||
return cores;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,137 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.alfresco.service.cmr.attributes.AttributeService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.inteligr8.alfresco.asie.Constants;
|
||||
import com.inteligr8.alfresco.asie.api.CoreAdminApi;
|
||||
import com.inteligr8.solr.model.ExceptionResponse;
|
||||
import com.inteligr8.solr.model.core.CreateRequest;
|
||||
import com.inteligr8.solr.model.core.ReloadRequest;
|
||||
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
import jakarta.ws.rs.InternalServerErrorException;
|
||||
|
||||
@Component(value = "webscript.com.inteligr8.alfresco.asie.enterprise.node.post")
|
||||
public class ReloadNodeWebScript extends AbstractAsieNodeWebScript {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
private final Pattern shardRangePattern = Pattern.compile("([0-9]+)-([0-9]+)");
|
||||
|
||||
@Autowired
|
||||
@Qualifier(Constants.QUALIFIER_ASIE)
|
||||
private AttributeService attrService;
|
||||
|
||||
@Override
|
||||
protected void execute(WebScriptRequest req, WebScriptResponse res, final String nodeHostname, final int nodePort)
|
||||
throws IOException {
|
||||
Serializable[] keys = new String[] {
|
||||
Constants.ATTR_ASIE,
|
||||
Constants.ATTR_UNLOADED_NODE_CORES,
|
||||
nodeHostname + ":" + nodePort
|
||||
};
|
||||
|
||||
Map<String, String> cores = this.fetchUnloadedCores(keys);
|
||||
cores.putAll(this.fetchOtherCores(req));
|
||||
if (cores.isEmpty())
|
||||
throw new WebScriptException(HttpStatus.NOT_FOUND.value(), "The specified node was not found or formulated");
|
||||
|
||||
boolean changed = false;
|
||||
|
||||
Iterator<Entry<String, String>> i = cores.entrySet().iterator();
|
||||
while (i.hasNext()) {
|
||||
Entry<String, String> core = i.next();
|
||||
String coreName = core.getKey();
|
||||
String coreInstancePath = core.getValue();
|
||||
|
||||
this.logger.info("Reloading core {} on ASIE node: {}", coreName, nodeHostname);
|
||||
CoreAdminApi api = this.createApi(nodeHostname, nodePort);
|
||||
try {
|
||||
api.create(new CreateRequest()
|
||||
.withCore(coreName)
|
||||
.withConfigDirectory(coreInstancePath));
|
||||
} catch (BadRequestException bre) {
|
||||
this.logger.warn("Core {} does not exist on ASIE node: {}; forgetting it", coreName, nodeHostname);
|
||||
i.remove();
|
||||
changed = true;
|
||||
} catch (InternalServerErrorException isee) {
|
||||
ExceptionResponse response = isee.getResponse().readEntity(ExceptionResponse.class);
|
||||
if (response.getError() == null || response.getError().getMessage() == null || !response.getError().getMessage().endsWith(" already exists."))
|
||||
throw isee;
|
||||
|
||||
this.logger.info("Core {} was already loaded on ASIE node: {}; reloading ...", coreName, nodeHostname);
|
||||
api.reload(new ReloadRequest()
|
||||
.withCore(coreName));
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
this.attrService.setAttribute((Serializable) cores, keys);
|
||||
|
||||
res.setStatus(HttpStatus.OK.value());
|
||||
}
|
||||
|
||||
private Map<String, String> fetchUnloadedCores(Serializable[] keys) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, String> cores = (Map<String, String>) this.attrService.getAttribute(keys);
|
||||
if (cores == null)
|
||||
cores = new HashMap<String, String>();
|
||||
return cores;
|
||||
}
|
||||
|
||||
private Map<String, String> fetchOtherCores(WebScriptRequest req) {
|
||||
String coreName = this.getOptionalQueryParameter(req, "coreName");
|
||||
if (coreName == null)
|
||||
coreName = this.getOptionalQueryParameter(req, "core");
|
||||
String shardRange = this.getOptionalQueryParameter(req, "shardRange");
|
||||
Short shardCount = this.getOptionalQueryParameter(req, "shardCount", Short.class);
|
||||
if (coreName == null || shardRange == null || shardCount == null)
|
||||
return Collections.emptyMap();
|
||||
|
||||
String template = this.getOptionalQueryParameter(req, "template");
|
||||
if (template == null)
|
||||
template = "rerank";
|
||||
Short nodeId = this.getOptionalQueryParameter(req, "nodeId", Short.class);
|
||||
if (nodeId == null)
|
||||
nodeId = 1;
|
||||
Short nodeCount = this.getOptionalQueryParameter(req, "nodeCount", Short.class);
|
||||
if (nodeCount == null)
|
||||
nodeCount = 2;
|
||||
|
||||
String baseConfigDirectory = template + "--" + coreName + "--shards--" + shardCount + "-x-1--node--" + nodeId + "-of-" + nodeCount;
|
||||
|
||||
Matcher matcher = this.shardRangePattern.matcher(shardRange);
|
||||
if (!matcher.find())
|
||||
throw new WebScriptException(HttpStatus.BAD_REQUEST.value(), "The 'shardRange' query parameter value is not formatted as expected");
|
||||
|
||||
Map<String, String> cores = new HashMap<>();
|
||||
|
||||
short startShardId = Short.parseShort(matcher.group(1));
|
||||
short endShardId = Short.parseShort(matcher.group(2));
|
||||
for (short shardId = startShardId; shardId <= endShardId; shardId++) {
|
||||
String shardConfigDirectory = baseConfigDirectory + "/" + coreName + "-" + shardId;
|
||||
cores.put(coreName, shardConfigDirectory);
|
||||
}
|
||||
|
||||
return cores;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest;
|
||||
|
||||
import org.alfresco.repo.index.shard.ShardState;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.inteligr8.alfresco.asie.enterprise.model.NodeShardParameterSet;
|
||||
import com.inteligr8.alfresco.asie.enterprise.model.ShardSet;
|
||||
|
||||
@Component(value = "webscript.com.inteligr8.alfresco.asie.enterprise.nodeShard.delete")
|
||||
public class UnloadNodeShardWebScript extends AbstractUnregisterNodeWebScript<NodeShardParameterSet> {
|
||||
|
||||
@Override
|
||||
protected NodeShardParameterSet createParameters(WebScriptRequest req, String nodeHostname, int nodePort) {
|
||||
ShardSet shardSet = this.getRequiredPathParameter(req, "shardSet", ShardSet.class);
|
||||
int shardId = this.getRequiredPathParameter(req, "shardId", Integer.class);
|
||||
|
||||
return new NodeShardParameterSet(nodeHostname, nodePort, shardSet, shardId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean matches(NodeShardParameterSet params, ShardState shardState) {
|
||||
if (!params.getShardSet().isFor(shardState))
|
||||
return false;
|
||||
if (params.getShardId() != shardState.getShardInstance().getShard().getInstance())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest;
|
||||
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.inteligr8.alfresco.asie.model.NodeParameterSet;
|
||||
|
||||
@Component(value = "webscript.com.inteligr8.alfresco.asie.enterprise.node.delete")
|
||||
public class UnloadNodeWebScript extends AbstractUnregisterNodeWebScript<NodeParameterSet> {
|
||||
|
||||
@Override
|
||||
protected NodeParameterSet createParameters(WebScriptRequest req, String nodeHostname, int nodePort) {
|
||||
return new NodeParameterSet(nodeHostname, nodePort);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest.model;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.alfresco.repo.index.shard.ShardInstance;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public abstract class NodeInfo {
|
||||
|
||||
public static String determineId(ShardInstance nodeCache) {
|
||||
int lastSlash = nodeCache.getBaseUrl().lastIndexOf('/');
|
||||
return nodeCache.getHostName() + ":" + nodeCache.getPort() + nodeCache.getBaseUrl().substring(0, lastSlash);
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
private String id;
|
||||
|
||||
@JsonProperty
|
||||
private Map<Integer, ShardInfo> shards;
|
||||
|
||||
public NodeInfo() {
|
||||
}
|
||||
|
||||
public NodeInfo(ShardInstance nodeCache) {
|
||||
this.setId(determineId(nodeCache));
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Map<Integer, ShardInfo> getShards() {
|
||||
if (shards == null)
|
||||
shards = new TreeMap<>();
|
||||
return shards;
|
||||
}
|
||||
|
||||
public void setShards(Map<Integer, ShardInfo> shards) {
|
||||
this.shards = shards;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest.model;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.index.shard.ShardInstance;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
@JsonInclude(Include.NON_EMPTY)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class NodeShardInfo extends NodeInfo {
|
||||
|
||||
@JsonProperty
|
||||
private Map<Integer, ShardInfo> shards;
|
||||
|
||||
public NodeShardInfo() {
|
||||
}
|
||||
|
||||
public NodeShardInfo(ShardInstance nodeCache) {
|
||||
super(nodeCache);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest.model;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.index.shard.Floc;
|
||||
import org.alfresco.repo.index.shard.ShardState;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.inteligr8.alfresco.asie.enterprise.model.ShardSet;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
@JsonInclude(Include.NON_EMPTY)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class PropertyHashShardSetInfo {
|
||||
|
||||
@JsonProperty
|
||||
private String methodSpec;
|
||||
|
||||
@JsonProperty
|
||||
private int shardCount;
|
||||
|
||||
@JsonProperty
|
||||
private Map<Object, ShardInfo> shards;
|
||||
|
||||
public PropertyHashShardSetInfo() {
|
||||
}
|
||||
|
||||
public PropertyHashShardSetInfo(Floc floc, ShardState anyShardNode) {
|
||||
ShardSet shardSet = new ShardSet(floc, anyShardNode);
|
||||
this.setMethodSpec(shardSet.toSpec());
|
||||
this.setShardCount(floc.getNumberOfShards());
|
||||
}
|
||||
|
||||
public String getMethodSpec() {
|
||||
return this.methodSpec;
|
||||
}
|
||||
|
||||
public void setMethodSpec(String methodSpec) {
|
||||
this.methodSpec = methodSpec;
|
||||
}
|
||||
|
||||
public int getShardCount() {
|
||||
return shardCount;
|
||||
}
|
||||
|
||||
public void setShardCount(int shardCount) {
|
||||
this.shardCount = shardCount;
|
||||
}
|
||||
|
||||
public Map<Object, ShardInfo> getShards() {
|
||||
return shards;
|
||||
}
|
||||
|
||||
public void setShards(Map<Object, ShardInfo> shards) {
|
||||
this.shards = shards;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,97 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest.model;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.index.shard.ShardState;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat.Shape;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
|
||||
@JsonInclude(Include.NON_EMPTY)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ShardInfo {
|
||||
|
||||
@JsonProperty
|
||||
private int id;
|
||||
|
||||
@JsonProperty
|
||||
private Long txsCompleted;
|
||||
|
||||
@JsonProperty
|
||||
private Long txsRemaining;
|
||||
|
||||
@JsonProperty
|
||||
@JsonFormat(shape = Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssXXX")
|
||||
private OffsetDateTime latestTx;
|
||||
|
||||
@JsonProperty
|
||||
private Map<String, NodeInfo> nodes;
|
||||
|
||||
@JsonProperty
|
||||
private ShardSetInfo shardSet;
|
||||
|
||||
public ShardInfo() {
|
||||
}
|
||||
|
||||
public ShardInfo(ShardState shard) {
|
||||
this.setId(shard.getShardInstance().getShard().getInstance());
|
||||
this.setLatestTx(OffsetDateTime.ofInstant(Instant.ofEpochMilli(shard.getLastIndexedTxCommitTime()), ZoneOffset.UTC));
|
||||
this.setTxsCompleted(shard.getLastIndexedTxId());
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getTxsCompleted() {
|
||||
return txsCompleted;
|
||||
}
|
||||
|
||||
public void setTxsCompleted(Long txsCompleted) {
|
||||
this.txsCompleted = txsCompleted;
|
||||
}
|
||||
|
||||
public Long getTxsRemaining() {
|
||||
return txsRemaining;
|
||||
}
|
||||
|
||||
public void setTxsRemaining(Long txsRemaining) {
|
||||
this.txsRemaining = txsRemaining;
|
||||
}
|
||||
|
||||
public OffsetDateTime getLatestTx() {
|
||||
return latestTx;
|
||||
}
|
||||
|
||||
public void setLatestTx(OffsetDateTime latestTx) {
|
||||
this.latestTx = latestTx;
|
||||
}
|
||||
|
||||
public Map<String, NodeInfo> getNodes() {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
public void setNodes(Map<String, NodeInfo> nodes) {
|
||||
this.nodes = nodes;
|
||||
}
|
||||
|
||||
public ShardSetInfo getShardSet() {
|
||||
return shardSet;
|
||||
}
|
||||
|
||||
public void setShardSet(ShardSetInfo shardSet) {
|
||||
this.shardSet = shardSet;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest.model;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
|
||||
import org.alfresco.repo.index.shard.ShardState;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat.Shape;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
@JsonInclude(Include.NON_EMPTY)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ShardNodeInfo extends NodeInfo {
|
||||
|
||||
@JsonProperty
|
||||
private Long txsCompleted;
|
||||
|
||||
@JsonProperty
|
||||
@JsonFormat(shape = Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssXXX")
|
||||
private OffsetDateTime latestTx;
|
||||
|
||||
public ShardNodeInfo() {
|
||||
}
|
||||
|
||||
public ShardNodeInfo(ShardState shard) {
|
||||
super(shard.getShardInstance());
|
||||
this.setLatestTx(OffsetDateTime.ofInstant(Instant.ofEpochMilli(shard.getLastIndexedTxCommitTime()), ZoneOffset.UTC));
|
||||
this.setTxsCompleted(shard.getLastIndexedTxId());
|
||||
}
|
||||
|
||||
public Long getTxsCompleted() {
|
||||
return txsCompleted;
|
||||
}
|
||||
|
||||
public void setTxsCompleted(Long txsCompleted) {
|
||||
this.txsCompleted = txsCompleted;
|
||||
}
|
||||
|
||||
public OffsetDateTime getLatestTx() {
|
||||
return latestTx;
|
||||
}
|
||||
|
||||
public void setLatestTx(OffsetDateTime latestTx) {
|
||||
this.latestTx = latestTx;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,73 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.rest.model;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.alfresco.repo.index.shard.Floc;
|
||||
import org.alfresco.repo.index.shard.ShardState;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.inteligr8.alfresco.asie.enterprise.model.ShardSet;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
@JsonInclude(Include.NON_EMPTY)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ShardSetInfo {
|
||||
|
||||
@JsonProperty
|
||||
private String methodSpec;
|
||||
|
||||
@JsonProperty
|
||||
private int shardCount;
|
||||
|
||||
@JsonProperty
|
||||
private Map<Integer, ShardInfo> shards;
|
||||
|
||||
@JsonProperty
|
||||
private Map<Integer, Set<Object>> shardHashSamples = new TreeMap<>();
|
||||
|
||||
public ShardSetInfo() {
|
||||
}
|
||||
|
||||
public ShardSetInfo(Floc floc, ShardState anyShardNode) {
|
||||
ShardSet shardSet = new ShardSet(floc, anyShardNode);
|
||||
this.methodSpec = shardSet.toSpec();
|
||||
this.setShardCount(floc.getNumberOfShards());
|
||||
}
|
||||
|
||||
public String getMethodSpec() {
|
||||
return this.methodSpec;
|
||||
}
|
||||
|
||||
public void setMethodSpec(String methodSpec) {
|
||||
this.methodSpec = methodSpec;
|
||||
}
|
||||
|
||||
public int getShardCount() {
|
||||
return shardCount;
|
||||
}
|
||||
|
||||
public void setShardCount(int shardCount) {
|
||||
this.shardCount = shardCount;
|
||||
}
|
||||
|
||||
public Map<Integer, ShardInfo> getShards() {
|
||||
return shards;
|
||||
}
|
||||
|
||||
public void setShards(Map<Integer, ShardInfo> shards) {
|
||||
this.shards = shards;
|
||||
}
|
||||
|
||||
public Map<Integer, Set<Object>> getShardHashSamples() {
|
||||
return shardHashSamples;
|
||||
}
|
||||
|
||||
public void setShardHashSamples(Map<Integer, Set<Object>> shardHashSamples) {
|
||||
this.shardHashSamples = shardHashSamples;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.service;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.alfresco.repo.index.shard.ShardInstance;
|
||||
import org.alfresco.repo.index.shard.ShardState;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class ShardAnalysisService {
|
||||
|
||||
public ShardInstance computeLeadShard(Collection<ShardState> shardNodesCache) {
|
||||
if (shardNodesCache.isEmpty())
|
||||
return null;
|
||||
|
||||
long latestTime = 0L;
|
||||
ShardInstance latestNode = null;
|
||||
|
||||
for (ShardState shardNodeCache : shardNodesCache) {
|
||||
if (latestTime < shardNodeCache.getLastIndexedTxCommitTime()) {
|
||||
latestNode = shardNodeCache.getShardInstance();
|
||||
latestTime = shardNodeCache.getLastIndexedTxCommitTime();
|
||||
}
|
||||
}
|
||||
|
||||
return latestNode;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,102 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.service;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.alfresco.repo.index.shard.Shard;
|
||||
import org.alfresco.repo.index.shard.ShardInstance;
|
||||
import org.alfresco.repo.index.shard.ShardState;
|
||||
import org.alfresco.service.cmr.attributes.AttributeService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.inteligr8.alfresco.asie.Constants;
|
||||
import com.inteligr8.alfresco.asie.enterprise.rest.model.NodeInfo;
|
||||
|
||||
@Component
|
||||
public class ShardBackupService {
|
||||
|
||||
private static final String ATTR_BACKUP_NODE = "backupNode";
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Autowired
|
||||
private ShardAnalysisService sas;
|
||||
|
||||
@Autowired
|
||||
@Qualifier(Constants.QUALIFIER_ASIE)
|
||||
private AttributeService attributeService;
|
||||
|
||||
@Value("${inteligr8.asie.backup.persistTimeMinutes}")
|
||||
private int persistTimeMinutes;
|
||||
|
||||
public String fetchNodeId(Collection<ShardState> shardNodes) {
|
||||
if (shardNodes.isEmpty())
|
||||
return null;
|
||||
|
||||
ShardState shardNode0 = shardNodes.iterator().next();
|
||||
ShardInstance node0Shard = shardNode0.getShardInstance();
|
||||
Shard shard = node0Shard.getShard();
|
||||
String shardKey = shard.getFloc().getShardMethod().name() + "~" + shard.getFloc().getNumberOfShards() + "~" + shard.getInstance();
|
||||
|
||||
PersistedNode backupNode = (PersistedNode) this.attributeService.getAttribute(Constants.ATTR_ASIE, ATTR_BACKUP_NODE, shardKey);
|
||||
this.logger.debug("Found backup node: {}", backupNode);
|
||||
|
||||
if (backupNode == null || backupNode.isExpired()) {
|
||||
ShardInstance backupShardInstance = this.sas.computeLeadShard(shardNodes);
|
||||
backupNode = new PersistedNode(NodeInfo.determineId(backupShardInstance));
|
||||
this.attributeService.setAttribute(backupNode, Constants.ATTR_ASIE, ATTR_BACKUP_NODE, shardKey);
|
||||
}
|
||||
|
||||
return backupNode.getNode();
|
||||
}
|
||||
|
||||
public void forget() {
|
||||
this.attributeService.removeAttribute(Constants.ATTR_ASIE, ATTR_BACKUP_NODE);
|
||||
}
|
||||
|
||||
public void forget(ShardState shardNode) {
|
||||
ShardInstance nodeShard = shardNode.getShardInstance();
|
||||
Shard shard = nodeShard.getShard();
|
||||
String shardKey = shard.getFloc().getShardMethod().name() + "~" + shard.getFloc().getNumberOfShards() + "~" + shard.getInstance();
|
||||
|
||||
this.attributeService.removeAttribute(Constants.ATTR_ASIE, ATTR_BACKUP_NODE, shardKey);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private class PersistedNode implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String node;
|
||||
private long expireTimeMillis;
|
||||
|
||||
PersistedNode(String node) {
|
||||
this.node = node;
|
||||
this.reset();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
this.expireTimeMillis = System.currentTimeMillis() + persistTimeMinutes * 60L * 1000L;
|
||||
}
|
||||
|
||||
boolean isExpired() {
|
||||
return this.expireTimeMillis < System.currentTimeMillis();
|
||||
}
|
||||
|
||||
String getNode() {
|
||||
return this.node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "node: " + this.node + "; expires in: " + (System.currentTimeMillis() - this.expireTimeMillis) + " ms";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,142 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.service;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.index.shard.Floc;
|
||||
import org.alfresco.repo.index.shard.Shard;
|
||||
import org.alfresco.repo.index.shard.ShardInstance;
|
||||
import org.alfresco.repo.index.shard.ShardMethodEnum;
|
||||
import org.alfresco.repo.index.shard.ShardRegistry;
|
||||
import org.alfresco.repo.index.shard.ShardState;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.inteligr8.alfresco.asie.Constants;
|
||||
import com.inteligr8.alfresco.asie.enterprise.model.ShardSet;
|
||||
|
||||
@Component
|
||||
public class ShardDiscoveryService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Autowired
|
||||
@Qualifier(Constants.BEAN_SHARD_REGISTRY)
|
||||
private ShardRegistry shardRegistry;
|
||||
|
||||
public Set<ShardState> findByNode(String nodeHostname, int nodePort) {
|
||||
Map<Floc, Map<Shard, Set<ShardState>>> flocs = this.shardRegistry.getFlocs();
|
||||
if (flocs.isEmpty())
|
||||
return Collections.emptySet();
|
||||
|
||||
Set<ShardState> shards = new HashSet<>();
|
||||
|
||||
for (Entry<Floc, Map<Shard, Set<ShardState>>> floc : flocs.entrySet()) {
|
||||
for (Entry<Shard, Set<ShardState>> flocShard : floc.getValue().entrySet()) {
|
||||
for (ShardState shardState : flocShard.getValue()) {
|
||||
ShardInstance shardInstance = shardState.getShardInstance();
|
||||
if (!nodeHostname.equalsIgnoreCase(shardInstance.getHostName())) {
|
||||
InetAddress nodeAddress = this.resolve(nodeHostname);
|
||||
if (nodeAddress == null)
|
||||
continue;
|
||||
|
||||
InetAddress shardInstanceAddress = this.resolve(shardInstance.getHostName());
|
||||
if (!nodeAddress.equals(shardInstanceAddress))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nodePort == shardInstance.getPort())
|
||||
shards.add(shardState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return shards;
|
||||
}
|
||||
|
||||
public Map<Shard, Set<ShardState>> findByShardSet(ShardSet shardSet) {
|
||||
Map<Floc, Map<Shard, Set<ShardState>>> flocs = this.shardRegistry.getFlocs();
|
||||
if (flocs.isEmpty())
|
||||
return Collections.emptyMap();
|
||||
this.logger.trace("Found {} shard sets", flocs.size());
|
||||
|
||||
for (Entry<Floc, Map<Shard, Set<ShardState>>> floc : flocs.entrySet()) {
|
||||
if (!floc.getKey().getShardMethod().equals(shardSet.getMethod()))
|
||||
continue;
|
||||
|
||||
if (!shardSet.getConfig().isEmpty()) {
|
||||
if (floc.getValue().isEmpty())
|
||||
continue;
|
||||
Shard firstShard = floc.getValue().keySet().iterator().next();
|
||||
|
||||
Set<ShardState> firstShardStates = floc.getValue().get(firstShard);
|
||||
if (firstShardStates == null || firstShardStates.isEmpty())
|
||||
continue;
|
||||
ShardState firstShardState = firstShardStates.iterator().next();
|
||||
|
||||
Map<String, String> firstShardProps = firstShardState.getPropertyBag();
|
||||
if (!shardSet.isConfigurationFor(firstShardProps))
|
||||
continue;
|
||||
}
|
||||
|
||||
return floc.getValue();
|
||||
}
|
||||
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
public Collection<Pair<Floc, Map<Shard, Set<ShardState>>>> findByShardMethod(ShardMethodEnum shardMethod) {
|
||||
Map<Floc, Map<Shard, Set<ShardState>>> flocs = this.shardRegistry.getFlocs();
|
||||
if (flocs.isEmpty())
|
||||
return Collections.emptyList();
|
||||
this.logger.trace("Found {} shard sets", flocs.size());
|
||||
|
||||
List<Pair<Floc, Map<Shard, Set<ShardState>>>> filteredFlocs = new LinkedList<>();
|
||||
|
||||
for (Entry<Floc, Map<Shard, Set<ShardState>>> floc : flocs.entrySet()) {
|
||||
if (!floc.getKey().getShardMethod().equals(shardMethod))
|
||||
continue;
|
||||
filteredFlocs.add(new Pair<>(floc.getKey(), floc.getValue()));
|
||||
}
|
||||
|
||||
return filteredFlocs;
|
||||
}
|
||||
|
||||
public Set<ShardState> findByShard(Map<Shard, Set<ShardState>> shards, int shardId) {
|
||||
if (shards == null)
|
||||
return null;
|
||||
|
||||
for (Entry<Shard, Set<ShardState>> shard : shards.entrySet()) {
|
||||
if (shard.getKey().getInstance() == shardId)
|
||||
return shard.getValue();
|
||||
}
|
||||
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
public Set<ShardState> findByShard(ShardSet shardSet, int shardId) {
|
||||
Map<Shard, Set<ShardState>> shards = this.findByShardSet(shardSet);
|
||||
return this.findByShard(shards, shardId);
|
||||
}
|
||||
|
||||
private InetAddress resolve(String hostname) {
|
||||
try {
|
||||
return InetAddress.getByName(hostname);
|
||||
} catch (UnknownHostException uhe) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
package com.inteligr8.alfresco.asie.enterprise.service;
|
||||
|
||||
import org.alfresco.repo.cache.SimpleCache;
|
||||
import org.alfresco.repo.index.shard.ShardInstance;
|
||||
import org.alfresco.repo.index.shard.ShardState;
|
||||
import org.alfresco.service.cmr.attributes.AttributeService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.inteligr8.alfresco.asie.Constants;
|
||||
|
||||
@Component
|
||||
public class ShardStateService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Autowired
|
||||
@Qualifier(Constants.QUALIFIER_ASIE)
|
||||
private AttributeService attrService;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("shardStateCache")
|
||||
private SimpleCache<ShardInstance, ShardState> shardStateCache;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("shardToGuidCache")
|
||||
private SimpleCache<ShardInstance, String> shardToGuidCache;
|
||||
|
||||
public void clear() {
|
||||
this.logger.info("Removing all nodes/shards from the shard registry");
|
||||
|
||||
// this clears the state from the backend database
|
||||
this.attrService.removeAttribute(Constants.ATTR_SHARD_STATE);
|
||||
this.attrService.removeAttribute(Constants.ATTR_SHARD_SUBSCRIPTION);
|
||||
|
||||
// this clears the state from Hazelcast
|
||||
this.shardStateCache.clear();
|
||||
this.shardToGuidCache.clear();
|
||||
}
|
||||
|
||||
public void clear(String guid) {
|
||||
this.logger.info("Removing node from the shard registry: {}", guid);
|
||||
|
||||
ShardState shardState = (ShardState) this.attrService.getAttribute(Constants.ATTR_SHARD_STATE, guid);
|
||||
|
||||
// this clears the state from the backend database
|
||||
this.attrService.removeAttribute(Constants.ATTR_SHARD_STATE, guid);
|
||||
this.attrService.removeAttribute(Constants.ATTR_SHARD_SUBSCRIPTION, guid);
|
||||
|
||||
// this clears the state from Hazelcast
|
||||
if (shardState != null) {
|
||||
this.shardStateCache.remove(shardState.getShardInstance());
|
||||
this.shardToGuidCache.remove(shardState.getShardInstance());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
package com.inteligr8.alfresco.asie.model;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
public class NodeParameterSet implements RequestParameterSet {
|
||||
|
||||
private String hostname;
|
||||
private int port;
|
||||
|
||||
public NodeParameterSet(String hostname, int port) {
|
||||
this.hostname = hostname;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public String getHostname() {
|
||||
return hostname;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public InetAddress getAddress() {
|
||||
try {
|
||||
return InetAddress.getByName(this.hostname);
|
||||
} catch (UnknownHostException uhe) {
|
||||
// suppress
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
package com.inteligr8.alfresco.asie.model;
|
||||
|
||||
public interface RequestParameterSet {
|
||||
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
package com.inteligr8.alfresco.asie.provider;
|
||||
|
||||
import org.alfresco.service.cmr.attributes.AttributeService;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import com.inteligr8.alfresco.asie.Constants;
|
||||
|
||||
@Configuration
|
||||
public class AttributeServiceProvider {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext context;
|
||||
|
||||
/**
|
||||
* This allows for the selection of the primary or first AttributeService
|
||||
* registered in the Spring BeanFactory. OOTB, there are multiple
|
||||
* AttributeService options and you would typically want
|
||||
* 'attributeService`. But an extension could have a @Primary that we
|
||||
* would want to use instead.
|
||||
*
|
||||
* @return An AttributeService.
|
||||
*/
|
||||
@Bean("asieAttributeService")
|
||||
@Qualifier(Constants.QUALIFIER_ASIE)
|
||||
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
|
||||
public AttributeService selectAttributeService() {
|
||||
return this.getPrimaryOrNamed(AttributeService.class, "attributeService");
|
||||
}
|
||||
|
||||
private <T> T getPrimaryOrNamed(Class<T> type, String beanName) {
|
||||
ObjectProvider<T> provider = this.context.getBeanProvider(type);
|
||||
|
||||
// this will select the primary or if there is just one impl, that one impl
|
||||
T t = provider.getIfUnique();
|
||||
if (t == null) {
|
||||
// this will select the named bean; throwing exception if there is none
|
||||
t = this.context.getBean(beanName, type);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
package com.inteligr8.alfresco.asie.provider;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.inteligr8.alfresco.asie.Constants;
|
||||
|
||||
@Configuration
|
||||
public class ObjectMapperProvider {
|
||||
|
||||
@Bean("asieObjectMapper")
|
||||
@Qualifier(Constants.QUALIFIER_ASIE)
|
||||
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
|
||||
public ObjectMapper createObjectMapper() {
|
||||
ObjectMapper om = new ObjectMapper();
|
||||
om.registerModule(new JavaTimeModule());
|
||||
om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
return om;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,227 @@
|
||||
package com.inteligr8.alfresco.asie.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.extensions.webscripts.AbstractWebScript;
|
||||
import org.springframework.extensions.webscripts.Description.RequiredAuthentication;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.inteligr8.alfresco.asie.Constants;
|
||||
import com.inteligr8.alfresco.asie.api.CoreAdminApi;
|
||||
import com.inteligr8.rs.AuthorizationFilter;
|
||||
import com.inteligr8.rs.Client;
|
||||
import com.inteligr8.rs.ClientCxfConfiguration;
|
||||
import com.inteligr8.rs.ClientCxfImpl;
|
||||
|
||||
import jakarta.ws.rs.client.ClientRequestContext;
|
||||
import net.sf.acegisecurity.GrantedAuthority;
|
||||
|
||||
public abstract class AbstractAsieWebScript extends AbstractWebScript implements InitializingBean {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Value("${solr.secureComms}")
|
||||
private String solrSecureComms;
|
||||
|
||||
@Value("${solr.port}")
|
||||
private int solrPort;
|
||||
|
||||
@Value("${solr.port.ssl}")
|
||||
private int solrSslPort;
|
||||
|
||||
@Value("${solr.sharedSecret.header}")
|
||||
private String solrSharedSecretHeader;
|
||||
|
||||
@Value("${solr.sharedSecret}")
|
||||
private String solrSharedSecret;
|
||||
|
||||
@Value("${inteligr8.asie.allowedAuthorities}")
|
||||
private String authorizedAuthoritiesStr;
|
||||
|
||||
@Value("${inteligr8.asie.basePath}")
|
||||
private String solrBaseUrl;
|
||||
|
||||
@Autowired
|
||||
@Qualifier(Constants.QUALIFIER_ASIE)
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
private Set<String> authorizedAuthorities;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
this.authorizedAuthorities = new HashSet<>();
|
||||
String[] authorities = this.authorizedAuthoritiesStr.split(",");
|
||||
for (String authority : authorities) {
|
||||
authority = StringUtils.trimToNull(authority);
|
||||
if (authority != null)
|
||||
this.authorizedAuthorities.add(authority);
|
||||
}
|
||||
|
||||
if (this.authorizedAuthorities.isEmpty())
|
||||
this.logger.warn("All authenticated users will be authorized to access ASIE web scripts");
|
||||
|
||||
this.solrSharedSecret = StringUtils.trimToNull(this.solrSharedSecret);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void execute(WebScriptRequest request, WebScriptResponse response) throws IOException {
|
||||
if (RequiredAuthentication.user.equals(this.getDescription().getRequiredAuthentication())) {
|
||||
if (!this.isAuthorized())
|
||||
throw new WebScriptException(HttpStatus.FORBIDDEN.value(), "You are not authorized for access this resource.");
|
||||
}
|
||||
|
||||
this.executeAuthorized(request, response);
|
||||
}
|
||||
|
||||
private boolean isAuthorized() {
|
||||
if (this.authorizedAuthorities.contains(AuthenticationUtil.getFullyAuthenticatedUser()))
|
||||
return true;
|
||||
for (GrantedAuthority auth : AuthenticationUtil.getFullAuthentication().getAuthorities()) {
|
||||
if (this.authorizedAuthorities.contains(auth.getAuthority()))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract void executeAuthorized(WebScriptRequest request, WebScriptResponse response) throws IOException;
|
||||
|
||||
public ObjectMapper getObjectMapper() {
|
||||
return objectMapper;
|
||||
}
|
||||
|
||||
protected CoreAdminApi createApi(String hostname, int port) {
|
||||
String solrBaseUrl = this.formulateSolrBaseUrl(hostname, port);
|
||||
this.logger.trace("Using Solr base URL: {}", solrBaseUrl);
|
||||
Client solrClient = this.createClient(solrBaseUrl);
|
||||
return this.getApi(solrClient);
|
||||
}
|
||||
|
||||
protected CoreAdminApi getApi(Client solrClient) {
|
||||
return solrClient.getApi(CoreAdminApi.class);
|
||||
}
|
||||
|
||||
protected int getDefaultSolrPort() {
|
||||
boolean isSsl = "https".equals(this.solrSecureComms);
|
||||
return isSsl ? this.solrSslPort : this.solrPort;
|
||||
}
|
||||
|
||||
protected String formulateSolrBaseUrl(WebScriptRequest req) {
|
||||
String hostname = this.getRequiredPathParameter(req, "hostname");
|
||||
Integer port = this.getOptionalPathParameter(req, "port", Integer.class);
|
||||
return this.formulateSolrBaseUrl(hostname, port);
|
||||
}
|
||||
|
||||
protected String formulateSolrBaseUrl(String hostname, Integer port) {
|
||||
boolean isSsl = "https".equals(this.solrSecureComms);
|
||||
StringBuilder baseUrl = new StringBuilder(isSsl ? "https" : "http").append("://").append(hostname);
|
||||
baseUrl.append(':').append(port == null ? (isSsl ? this.solrSslPort : this.solrPort) : port);
|
||||
baseUrl.append(this.solrBaseUrl);
|
||||
return baseUrl.toString();
|
||||
}
|
||||
|
||||
protected Client createClient(final String baseUrl) {
|
||||
ClientCxfImpl client = new ClientCxfImpl(new ClientCxfConfiguration() {
|
||||
@Override
|
||||
public String getBaseUrl() {
|
||||
return baseUrl.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizationFilter createAuthorizationFilter() {
|
||||
return solrSharedSecret == null ? null : new AuthorizationFilter() {
|
||||
@Override
|
||||
public void filter(ClientRequestContext requestContext) throws IOException {
|
||||
logger.debug("Adding authorization headers for ASIE shared auth: {}", solrSharedSecretHeader);
|
||||
requestContext.getHeaders().putSingle(solrSharedSecretHeader, solrSharedSecret);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDefaultBusEnabled() {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
client.register();
|
||||
return client;
|
||||
}
|
||||
|
||||
protected String getRequiredPathParameter(WebScriptRequest req, String pathParamName) {
|
||||
String pathParamValue = this.getOptionalPathParameter(req, pathParamName);
|
||||
if (pathParamValue == null)
|
||||
throw new WebScriptException(HttpStatus.BAD_REQUEST.value(), "The '" + pathParamName + "' path parameter is required");
|
||||
return pathParamValue;
|
||||
}
|
||||
|
||||
protected <T> T getRequiredPathParameter(WebScriptRequest req, String pathParamName, Class<T> type) {
|
||||
T pathParamValue = this.getOptionalPathParameter(req, pathParamName, type);
|
||||
if (pathParamValue == null)
|
||||
throw new WebScriptException(HttpStatus.BAD_REQUEST.value(), "The '" + pathParamName + "' path parameter is required");
|
||||
return pathParamValue;
|
||||
}
|
||||
|
||||
protected String getOptionalPathParameter(WebScriptRequest req, String pathParamName) {
|
||||
return StringUtils.trimToNull(req.getServiceMatch().getTemplateVars().get(pathParamName));
|
||||
}
|
||||
|
||||
protected <T> T getOptionalPathParameter(WebScriptRequest req, String pathParamName, Class<T> type) {
|
||||
String str = StringUtils.trimToNull(req.getServiceMatch().getTemplateVars().get(pathParamName));
|
||||
return this.getOptionalParameter(req, pathParamName, str, "path element", type);
|
||||
}
|
||||
|
||||
protected String getOptionalQueryParameter(WebScriptRequest req, String queryParamName) {
|
||||
return StringUtils.trimToNull(req.getParameter(queryParamName));
|
||||
}
|
||||
|
||||
protected <T> T getOptionalQueryParameter(WebScriptRequest req, String queryParamName, Class<T> type) {
|
||||
String str = StringUtils.trimToNull(req.getParameter(queryParamName));
|
||||
return this.getOptionalParameter(req, queryParamName, str, "query parameter", type);
|
||||
}
|
||||
|
||||
protected <T> T getOptionalParameter(WebScriptRequest req, String paramName, String paramValue, String paramTypeDisplay, Class<T> type) {
|
||||
if (paramValue == null)
|
||||
return null;
|
||||
if (type.equals(String.class))
|
||||
return type.cast(paramValue);
|
||||
|
||||
try {
|
||||
try {
|
||||
Constructor<T> constructor = type.getConstructor(String.class);
|
||||
return constructor.newInstance(paramValue);
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
Method method = type.getDeclaredMethod("valueOf", String.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
T t = (T) method.invoke(null, paramValue);
|
||||
return t;
|
||||
}
|
||||
} catch (InvocationTargetException ite) {
|
||||
if (ite.getTargetException() instanceof NumberFormatException) {
|
||||
throw new WebScriptException(HttpStatus.BAD_REQUEST.value(), "The `" + paramName + "` " + paramTypeDisplay + " '" + paramValue + "' must be a number");
|
||||
} else {
|
||||
throw new WebScriptException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "An unexpected issue occurred", ite);
|
||||
}
|
||||
} catch (NoSuchMethodException | IllegalAccessException | InstantiationException e) {
|
||||
throw new WebScriptException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "An unexpected issue occurred", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
package com.inteligr8.alfresco.asie.service;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.apache.commons.codec.digest.MurmurHash3;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class SolrShardHashService {
|
||||
|
||||
private final Charset charset = Charset.forName("utf-8");
|
||||
|
||||
public int hash(Object obj, int shardCount) {
|
||||
String str = obj.toString();
|
||||
byte[] bytes = str.getBytes(this.charset);
|
||||
|
||||
// From ASIE source:
|
||||
// Math.abs(Hash.murmurhash3_x86_32(shardBy, 0, shardBy.length(), 66)) % shardCount
|
||||
|
||||
// Using Apache Commons Codec:
|
||||
MurmurHash3.IncrementalHash32x86 hash = new MurmurHash3.IncrementalHash32x86();
|
||||
hash.start(66);
|
||||
hash.add(bytes, 0, bytes.length);
|
||||
return Math.abs(hash.end()) % shardCount;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
<webscript xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://bitbucket.org/!api/2.0/snippets/inteligr8/AzMgbp/80fdd26a6b3769a63cdc6b54bf1f39e378545cf7/files/snippet.txt">
|
||||
|
||||
<!-- Naming & Organization -->
|
||||
<shortname>Retrieve Backup ASIE Node for ASIE Shard</shortname>
|
||||
<family>Inteligr8 ASIE</family>
|
||||
<description><![CDATA[
|
||||
<p>Retrieve a reference to the ASIE node that should be used for the backup of the specified ASIE shard registered with ACS.</p>
|
||||
<p>The following path parameters are expected:</p>
|
||||
<dl>
|
||||
<dt>shardSet</dt>
|
||||
<dd>A shard method combined with its distinguishing properties;
|
||||
methods: MOD_ACL_ID, ACL_ID, DB_ID, DB_ID_RANGE, DATE, PROPERTY, EXPLICIT_ID;
|
||||
e.g. PROPERTY;key:cm:created;regex:^d{4} or DB_ID</dd>
|
||||
<dt>shardId</dt>
|
||||
<dd>A number starting at 1</dd>
|
||||
</dl>
|
||||
<p>The response will have the following format:</p>
|
||||
<pre>"hostname:port/baseUrl"</pre>
|
||||
<p>This is meant to help determine which shard should be backed up.
|
||||
The node is computed based on the lead shard on the first request.
|
||||
That value is cached until a reques isn't made for at least a configurable amount of time.</p>
|
||||
<p>The following status codes should be expected:</p>
|
||||
<dl>
|
||||
<dt>200</dt>
|
||||
<dd>OK</dd>
|
||||
<dt>204</dt>
|
||||
<dd>No ASIE node/shard information available</dd>
|
||||
<dt>400</dt>
|
||||
<dd>The path parameters are invalid</dd>
|
||||
<dt>404</dt>
|
||||
<dd>The specified shard set or shard ID could not be found</dd>
|
||||
</dl>
|
||||
]]></description>
|
||||
|
||||
<!-- Endpoint Configuration -->
|
||||
<url>/inteligr8/asie/shard/{shardSet}/{shardId}/backup</url>
|
||||
<format default="json">any</format>
|
||||
|
||||
<!-- Security -->
|
||||
<authentication>none</authentication>
|
||||
|
||||
<!-- Functionality -->
|
||||
<cache>
|
||||
<never>false</never>
|
||||
<public>false</public>
|
||||
</cache>
|
||||
|
||||
</webscript>
|
@@ -0,0 +1,45 @@
|
||||
<webscript xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://bitbucket.org/!api/2.0/snippets/inteligr8/AzMgbp/80fdd26a6b3769a63cdc6b54bf1f39e378545cf7/files/snippet.txt">
|
||||
|
||||
<!-- Naming & Organization -->
|
||||
<shortname>Retrieve Lead ASIE Node for ASIE Shard</shortname>
|
||||
<family>Inteligr8 ASIE</family>
|
||||
<description><![CDATA[
|
||||
<p>Retrieve a reference to the most current/up-to-date ASIE node for the specified ASIE shard registered with ACS.</p>
|
||||
<p>The following path parameters are expected:</p>
|
||||
<dl>
|
||||
<dt>shardSet</dt>
|
||||
<dd>A shard method combined with its distinguishing properties;
|
||||
methods: MOD_ACL_ID, ACL_ID, DB_ID, DB_ID_RANGE, DATE, PROPERTY, EXPLICIT_ID;
|
||||
e.g. PROPERTY;key:cm:created;regex:^d{4} or DB_ID</dd>
|
||||
<dt>shardId</dt>
|
||||
<dd>A number starting at 1</dd>
|
||||
</dl>
|
||||
<p>The response will have the following format:</p>
|
||||
<pre>"hostname:port/baseUrl"</pre>
|
||||
<dl>
|
||||
<dt>200</dt>
|
||||
<dd>OK</dd>
|
||||
<dt>204</dt>
|
||||
<dd>No ASIE node/shard information available</dd>
|
||||
<dt>400</dt>
|
||||
<dd>The path parameters are invalid</dd>
|
||||
<dt>404</dt>
|
||||
<dd>The specified shard set or shard ID could not be found</dd>
|
||||
</dl>
|
||||
]]></description>
|
||||
|
||||
<!-- Endpoint Configuration -->
|
||||
<url>/inteligr8/asie/shard/{shardSet}/{shardId}/lead</url>
|
||||
<format default="json">any</format>
|
||||
|
||||
<!-- Security -->
|
||||
<authentication>none</authentication>
|
||||
|
||||
<!-- Functionality -->
|
||||
<cache>
|
||||
<never>false</never>
|
||||
<public>false</public>
|
||||
</cache>
|
||||
|
||||
</webscript>
|
@@ -0,0 +1,40 @@
|
||||
<webscript xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://bitbucket.org/!api/2.0/snippets/inteligr8/AzMgbp/80fdd26a6b3769a63cdc6b54bf1f39e378545cf7/files/snippet.txt">
|
||||
|
||||
<!-- Naming & Organization -->
|
||||
<shortname>Clears ASIE Node from Registry</shortname>
|
||||
<family>Inteligr8 ASIE</family>
|
||||
<description><![CDATA[
|
||||
<p>Clears meta-data about all ASIE shards on a single ASIE node registered with ACS.
|
||||
This call will attempt to unload all shards on the ASIE node to prevent automatic registration on its next index attempt.
|
||||
If that disablement fails, this call will continue to unregister all shards on the node from ACS; however, they will automatically register again on its next indexing attempt.</p>
|
||||
<p>The following path parameters are expected:</p>
|
||||
<dl>
|
||||
<dt>nodeEndpoint</dt>
|
||||
<dd>A hostname or hostname:port for the ASIE node</dd>
|
||||
</dl>
|
||||
<p>The following status codes should be expected:</p>
|
||||
<dl>
|
||||
<dt>200</dt>
|
||||
<dd>OK</dd>
|
||||
<dt>400</dt>
|
||||
<dd>The path parameters are invalid</dd>
|
||||
<dt>404</dt>
|
||||
<dd>The specified ASIE node could not be found</dd>
|
||||
</dl>
|
||||
]]></description>
|
||||
|
||||
<!-- Endpoint Configuration -->
|
||||
<url>/inteligr8/asie/node/{nodeEndpoint}/shards</url>
|
||||
<url>/inteligr8/asie/node/{nodeEndpoint}</url>
|
||||
|
||||
<!-- Security -->
|
||||
<authentication>admin</authentication>
|
||||
|
||||
<!-- Functionality -->
|
||||
<cache>
|
||||
<never>false</never>
|
||||
<public>false</public>
|
||||
</cache>
|
||||
|
||||
</webscript>
|
@@ -0,0 +1,69 @@
|
||||
<webscript xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://bitbucket.org/!api/2.0/snippets/inteligr8/AzMgbp/80fdd26a6b3769a63cdc6b54bf1f39e378545cf7/files/snippet.txt">
|
||||
|
||||
<!-- Naming & Organization -->
|
||||
<shortname>Retrieves ASIE Node Information/Status</shortname>
|
||||
<family>Inteligr8 ASIE</family>
|
||||
<description><![CDATA[
|
||||
<p>Retrieves meta-data about all shards on a single ASIE node as registred with ACS.</p>
|
||||
<p>The following query parameter is supported:</p>
|
||||
<dl>
|
||||
<dt>nodeEndpoint</dt>
|
||||
<dd>A hostname or hostname:port for the ASIE node; dots are not allowed, you may use _ (underscore) instead</dd>
|
||||
<dt>sampleType</dt>
|
||||
<dd>A sample hash type; Sample hash types: PropertyYear, PropertyQuarter, PropertyMonth, PropertyWeek</dd>
|
||||
</dl>
|
||||
<p>The response will have the following format:</p>
|
||||
<pre>{
|
||||
"url": string,
|
||||
"hostname": string,
|
||||
"shards": {
|
||||
"string": { // shard ID as string
|
||||
"id": number,
|
||||
"txsCompleted": number,
|
||||
"txsRemaining": number,
|
||||
"latestTx": "datetime",
|
||||
"shardSet": {
|
||||
"id": "string", // generated shard set ID
|
||||
"method": "string",
|
||||
"methodDetail": "string",
|
||||
"hasContent": boolean,
|
||||
"shardCount": number,
|
||||
"shardHashSamples": {
|
||||
"string": [ // shard ID as string
|
||||
"string": // year as string
|
||||
],
|
||||
...
|
||||
}
|
||||
}
|
||||
},
|
||||
...
|
||||
]
|
||||
}</pre>
|
||||
<p>The following status codes should be expected:</p>
|
||||
<dl>
|
||||
<dt>200</dt>
|
||||
<dd>OK</dd>
|
||||
<dt>204</dt>
|
||||
<dd>No ASIE shard information available</dd>
|
||||
<dt>400</dt>
|
||||
<dd>The path or query parameters are invalid</dd>
|
||||
<dt>404</dt>
|
||||
<dd>The specified ASIE node instance could not be found</dd>
|
||||
</dl>
|
||||
]]></description>
|
||||
|
||||
<!-- Endpoint Configuration -->
|
||||
<url>/inteligr8/asie/node/{nodeEndpoint}?sampleHashType={sampleHashType?}</url>
|
||||
<format default="json">any</format>
|
||||
|
||||
<!-- Security -->
|
||||
<authentication>admin</authentication>
|
||||
|
||||
<!-- Functionality -->
|
||||
<cache>
|
||||
<never>false</never>
|
||||
<public>false</public>
|
||||
</cache>
|
||||
|
||||
</webscript>
|
@@ -0,0 +1,42 @@
|
||||
<webscript xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://bitbucket.org/!api/2.0/snippets/inteligr8/AzMgbp/80fdd26a6b3769a63cdc6b54bf1f39e378545cf7/files/snippet.txt">
|
||||
|
||||
<!-- Naming & Organization -->
|
||||
<shortname>Adds ASIE Node to Registry</shortname>
|
||||
<family>Inteligr8 ASIE</family>
|
||||
<description><![CDATA[
|
||||
<p>Loads all previously registered ASIE shards on a single ASIE node, which will eventually register with ACS.</p>
|
||||
<p>The following path parameters are expected:</p>
|
||||
<dl>
|
||||
<dt>nodeEndpoint</dt>
|
||||
<dd>A hostname or hostname:port for the ASIE node</dd>
|
||||
<dt>coreName</dt>
|
||||
<dd>A core name to restore in addition to known cores</dd>
|
||||
<dt>shardRange</dt>
|
||||
<dd>A shard range restore in addition to known shards (e.g. 0-7)</dd>
|
||||
</dl>
|
||||
<p>The following status codes should be expected:</p>
|
||||
<dl>
|
||||
<dt>200</dt>
|
||||
<dd>OK</dd>
|
||||
<dt>400</dt>
|
||||
<dd>The path parameters are invalid</dd>
|
||||
<dt>404</dt>
|
||||
<dd>The specified ASIE node was not previously registered</dd>
|
||||
</dl>
|
||||
]]></description>
|
||||
|
||||
<!-- Endpoint Configuration -->
|
||||
<url>/inteligr8/asie/node/{nodeEndpoint}/shards?coreName={coreName?}&shardRange={shardRange?}&template={template?}&shardCount={shardCount?}&nodeId={nodeId?}&nodeCount={nodeCount?}</url>
|
||||
<url>/inteligr8/asie/node/{nodeEndpoint}?coreName={coreName?}&shardRange={shardRange?}&template={template?}&shardCount={shardCount?}&nodeId={nodeId?}&nodeCount={nodeCount?}</url>
|
||||
|
||||
<!-- Security -->
|
||||
<authentication>admin</authentication>
|
||||
|
||||
<!-- Functionality -->
|
||||
<cache>
|
||||
<never>false</never>
|
||||
<public>false</public>
|
||||
</cache>
|
||||
|
||||
</webscript>
|
@@ -0,0 +1,45 @@
|
||||
<webscript xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://bitbucket.org/!api/2.0/snippets/inteligr8/AzMgbp/80fdd26a6b3769a63cdc6b54bf1f39e378545cf7/files/snippet.txt">
|
||||
|
||||
<!-- Naming & Organization -->
|
||||
<shortname>Clears ASIE Node/Shard from Registry</shortname>
|
||||
<family>Inteligr8 ASIE</family>
|
||||
<description><![CDATA[
|
||||
<p>Clears meta-data about a single ASIE shard on a single ASIE node registred with ACS.
|
||||
This call will attempt to disable further indexing by the ASIE node of only that shard to prevent automatic registration on its next index attempt.
|
||||
If that disablement fails, this call will continue to unregister the node/shard from ACS; however, it will automatically register again on its next indexing attempt.</p>
|
||||
<p>The following path parameters are expected:</p>
|
||||
<dl>
|
||||
<dt>nodeEndpoint</dt>
|
||||
<dd>A hostname or hostname:port for the ASIE node</dd>
|
||||
<dt>shardSet</dt>
|
||||
<dd>A shard method combined with its distinguishing properties;
|
||||
methods: MOD_ACL_ID, ACL_ID, DB_ID, DB_ID_RANGE, DATE, PROPERTY, EXPLICIT_ID;
|
||||
e.g. PROPERTY;key:cm:created;regex:^d{4} or DB_ID</dd>
|
||||
<dt>shardId</dt>
|
||||
<dd>A number starting at 1</dd>
|
||||
</dl>
|
||||
<p>The following status codes should be expected:</p>
|
||||
<dl>
|
||||
<dt>200</dt>
|
||||
<dd>OK</dd>
|
||||
<dt>400</dt>
|
||||
<dd>The path parameters are invalid</dd>
|
||||
<dt>404</dt>
|
||||
<dd>The specified ASIE node, shard set, or shard ID could not be found</dd>
|
||||
</dl>
|
||||
]]></description>
|
||||
|
||||
<!-- Endpoint Configuration -->
|
||||
<url>/inteligr8/asie/node/{nodeEndpoint}/shard/{shardSet}/{shardId}</url>
|
||||
|
||||
<!-- Security -->
|
||||
<authentication>admin</authentication>
|
||||
|
||||
<!-- Functionality -->
|
||||
<cache>
|
||||
<never>false</never>
|
||||
<public>false</public>
|
||||
</cache>
|
||||
|
||||
</webscript>
|
@@ -0,0 +1,41 @@
|
||||
<webscript xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://bitbucket.org/!api/2.0/snippets/inteligr8/AzMgbp/80fdd26a6b3769a63cdc6b54bf1f39e378545cf7/files/snippet.txt">
|
||||
|
||||
<!-- Naming & Organization -->
|
||||
<shortname>Adds ASIE Node to Registry</shortname>
|
||||
<family>Inteligr8 ASIE</family>
|
||||
<description><![CDATA[
|
||||
<p>Loads an ASIE shard on a single ASIE node, which will eventually register with ACS.</p>
|
||||
<p>The following path parameters are expected:</p>
|
||||
<dl>
|
||||
<dt>nodeEndpoint</dt>
|
||||
<dd>A hostname or hostname:port for the ASIE node</dd>
|
||||
<dt>shardCore</dt>
|
||||
<dd>A core name (prefix) for the ASIE shard (e.g. alfresco)</dd>
|
||||
<dt>shardId</dt>
|
||||
<dd>A numeric shard ID for the ASIE shard (e.g. 0)</dd>
|
||||
</dl>
|
||||
<p>The following status codes should be expected:</p>
|
||||
<dl>
|
||||
<dt>200</dt>
|
||||
<dd>OK</dd>
|
||||
<dt>400</dt>
|
||||
<dd>The path parameters are invalid</dd>
|
||||
<dt>404</dt>
|
||||
<dd>The specified ASIE node could not be found</dd>
|
||||
</dl>
|
||||
]]></description>
|
||||
|
||||
<!-- Endpoint Configuration -->
|
||||
<url>/inteligr8/asie/node/{nodeEndpoint}/shard/{shardCore}/{shardId}</url>
|
||||
|
||||
<!-- Security -->
|
||||
<authentication>admin</authentication>
|
||||
|
||||
<!-- Functionality -->
|
||||
<cache>
|
||||
<never>false</never>
|
||||
<public>false</public>
|
||||
</cache>
|
||||
|
||||
</webscript>
|
@@ -0,0 +1,65 @@
|
||||
<webscript xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://bitbucket.org/!api/2.0/snippets/inteligr8/AzMgbp/80fdd26a6b3769a63cdc6b54bf1f39e378545cf7/files/snippet.txt">
|
||||
|
||||
<!-- Naming & Organization -->
|
||||
<shortname>Retrieve ASIE Node Information/Status</shortname>
|
||||
<family>Inteligr8 ASIE</family>
|
||||
<description><![CDATA[
|
||||
<p>Retrieve meta-data about the ASIE nodes and their shards registered with ACS.</p>
|
||||
<p>The following query parameter is supported:</p>
|
||||
<dl>
|
||||
<dt>sampleHashType</dt>
|
||||
<dd>A sample hash type; Sample hash types: PropertyYear, PropertyQuarter, PropertyMonth, PropertyWeek</dd>
|
||||
</dl>
|
||||
<p>The response will have the following format:</p>
|
||||
<pre>{
|
||||
"nodes": {
|
||||
"string": { // node URL
|
||||
"id": "string",
|
||||
"shards": {
|
||||
"string": { // shard ID as string
|
||||
"id": number,
|
||||
"txsCompleted": number,
|
||||
"txsRemaining": number,
|
||||
"latestTx": "datetime",
|
||||
"shardSet": {
|
||||
"methodSpec": "string", // generated shard set ID
|
||||
"shardCount": number,
|
||||
"shardHashSamples": {
|
||||
"string": [ // shard ID as string
|
||||
"string": // year as string
|
||||
],
|
||||
...
|
||||
}
|
||||
}
|
||||
},
|
||||
...
|
||||
}
|
||||
}
|
||||
}
|
||||
}</pre>
|
||||
<p>The following status codes should be expected:</p>
|
||||
<dl>
|
||||
<dt>200</dt>
|
||||
<dd>OK</dd>
|
||||
<dt>204</dt>
|
||||
<dd>No ASIE shard information available</dd>
|
||||
<dt>400</dt>
|
||||
<dd>The query parameter is invalid</dd>
|
||||
</dl>
|
||||
]]></description>
|
||||
|
||||
<!-- Endpoint Configuration -->
|
||||
<url>/inteligr8/asie/nodes?sampleHashType={sampleHashType?}</url>
|
||||
<format default="json">any</format>
|
||||
|
||||
<!-- Security -->
|
||||
<authentication>admin</authentication>
|
||||
|
||||
<!-- Functionality -->
|
||||
<cache>
|
||||
<never>false</never>
|
||||
<public>false</public>
|
||||
</cache>
|
||||
|
||||
</webscript>
|
@@ -0,0 +1,72 @@
|
||||
<webscript xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://bitbucket.org/!api/2.0/snippets/inteligr8/AzMgbp/80fdd26a6b3769a63cdc6b54bf1f39e378545cf7/files/snippet.txt">
|
||||
|
||||
<!-- Naming & Organization -->
|
||||
<shortname>Retrieve ASIE Shard Hash Status</shortname>
|
||||
<family>Inteligr8 ASIE</family>
|
||||
<description><![CDATA[
|
||||
<p>Retrieve meta-data about the ASIE shard hashes of the `PROPERTY` method registered with ACS.
|
||||
Sample hashes are performed given the query parameters, which allows for reverse hashes of those samples in the response.
|
||||
A min/max or an enumerated list of values must also be provided.</p>
|
||||
<p>The following path and query parameters is expected or supported:</p>
|
||||
<dl>
|
||||
<dt>sampleHashType</dt>
|
||||
<dd>PropertyYear, PropertyQuarter, PropertyMonth, PropertyWeek</dd>
|
||||
<dt>shards</dt>
|
||||
<dd>The total number of shards expected</dd>
|
||||
<dt>min</dt>
|
||||
<dd>For numerical hashes, the minimum of an integer range to compute sample hashes</dd>
|
||||
<dt>max</dt>
|
||||
<dd>For numerical hashes, the maximum of an integer range to compute sample hashes</dd>
|
||||
<dt>values</dt>
|
||||
<dd>For any hashes, a comma-delimited enumeration of values to compute sample hashes</dd>
|
||||
</dl>
|
||||
<p>The response will have the following format:</p>
|
||||
<pre>[
|
||||
{
|
||||
"methodSpec": "string", // generated shard set ID
|
||||
"shardCount": number
|
||||
"shards": {
|
||||
"string": { // hash
|
||||
"id": number,
|
||||
"txsCompleted": number,
|
||||
"txsRemaining": number,
|
||||
"latestTx": "datetime",
|
||||
"nodes": {
|
||||
"string": { // ASIE node URL
|
||||
"url": "string",
|
||||
"hostname": "string"
|
||||
},
|
||||
...
|
||||
}
|
||||
},
|
||||
...
|
||||
}
|
||||
},
|
||||
...
|
||||
]</pre>
|
||||
<p>The following status codes should be expected:</p>
|
||||
<dl>
|
||||
<dt>200</dt>
|
||||
<dd>OK</dd>
|
||||
<dt>204</dt>
|
||||
<dd>No ASIE PROPERTY shard information available</dd>
|
||||
<dt>400</dt>
|
||||
<dd>The path or query parameters are invalid</dd>
|
||||
</dl>
|
||||
]]></description>
|
||||
|
||||
<!-- Endpoint Configuration -->
|
||||
<url>/inteligr8/asie/shards/byHash/{sampleHashType}/{shards}?min={min?}&max={max?}&values={values?}</url>
|
||||
<format default="json">any</format>
|
||||
|
||||
<!-- Security -->
|
||||
<authentication>admin</authentication>
|
||||
|
||||
<!-- Functionality -->
|
||||
<cache>
|
||||
<never>false</never>
|
||||
<public>false</public>
|
||||
</cache>
|
||||
|
||||
</webscript>
|
@@ -0,0 +1,32 @@
|
||||
<webscript xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://bitbucket.org/!api/2.0/snippets/inteligr8/AzMgbp/80fdd26a6b3769a63cdc6b54bf1f39e378545cf7/files/snippet.txt">
|
||||
|
||||
<!-- Naming & Organization -->
|
||||
<shortname>Clear ASIE Node/Shard Registry</shortname>
|
||||
<family>Inteligr8 ASIE</family>
|
||||
<description><![CDATA[
|
||||
<p>Clears all meta-data about the ASIE shard nodes and instances registred with ACS.
|
||||
This is more extreme than the OOTB purge capability, which sometimes errors rather than purging.
|
||||
This will avoid those errors, clearing all shard registration information regardless of how mess up they may be.</p>
|
||||
<p>If there are no shards, this will effectively do nothing.</p>
|
||||
<p>The following status codes should be expected:</p>
|
||||
<dl>
|
||||
<dt>200</dt>
|
||||
<dd>OK</dd>
|
||||
</dl>
|
||||
]]></description>
|
||||
|
||||
<!-- Endpoint Configuration -->
|
||||
<url>/inteligr8/asie/shards</url>
|
||||
<url>/inteligr8/asie/nodes</url>
|
||||
|
||||
<!-- Security -->
|
||||
<authentication>admin</authentication>
|
||||
|
||||
<!-- Functionality -->
|
||||
<cache>
|
||||
<never>false</never>
|
||||
<public>false</public>
|
||||
</cache>
|
||||
|
||||
</webscript>
|
@@ -0,0 +1,58 @@
|
||||
<webscript xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://bitbucket.org/!api/2.0/snippets/inteligr8/AzMgbp/80fdd26a6b3769a63cdc6b54bf1f39e378545cf7/files/snippet.txt">
|
||||
|
||||
<!-- Naming & Organization -->
|
||||
<shortname>Compute ASIE Sample Hash Table</shortname>
|
||||
<family>Inteligr8 ASIE</family>
|
||||
<description><![CDATA[
|
||||
<p>Compute sample hashes.
|
||||
Sample hashes are performed given the query parameters, which allows for reverse hashes of those samples in the response.
|
||||
A min/max or an enumerated list of values must also be provided.</p>
|
||||
<p>The following path and query parameters is expected or supported:</p>
|
||||
<dl>
|
||||
<dt>shards</dt>
|
||||
<dd>The total number of shards expected</dd>
|
||||
<dt>min</dt>
|
||||
<dd>For numerical hashes, the minimum of an integer range to compute sample hashes</dd>
|
||||
<dt>max</dt>
|
||||
<dd>For numerical hashes, the maximum of an integer range to compute sample hashes</dd>
|
||||
<dt>values</dt>
|
||||
<dd>For any hashes, a comma-delimited enumeration of values to compute sample hashes</dd>
|
||||
</dl>
|
||||
<p>The response will have the following format:</p>
|
||||
<pre>{
|
||||
"forward": {
|
||||
"string": number, // sample value to shard ID
|
||||
...
|
||||
},
|
||||
"reverse": {
|
||||
"number": [ // shard ID, starting at 0
|
||||
"string", // sample value
|
||||
...
|
||||
],
|
||||
...
|
||||
}
|
||||
}</pre>
|
||||
<p>The following status codes should be expected:</p>
|
||||
<dl>
|
||||
<dt>200</dt>
|
||||
<dd>OK</dd>
|
||||
<dt>400</dt>
|
||||
<dd>The path or query parameters are invalid</dd>
|
||||
</dl>
|
||||
]]></description>
|
||||
|
||||
<!-- Endpoint Configuration -->
|
||||
<url>/inteligr8/asie/hash/{shards}?min={min?}&max={max?}&values={values?}</url>
|
||||
<format default="json">any</format>
|
||||
|
||||
<!-- Security -->
|
||||
<authentication>admin</authentication>
|
||||
|
||||
<!-- Functionality -->
|
||||
<cache>
|
||||
<never>false</never>
|
||||
<public>false</public>
|
||||
</cache>
|
||||
|
||||
</webscript>
|
@@ -0,0 +1,73 @@
|
||||
<webscript xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://bitbucket.org/!api/2.0/snippets/inteligr8/AzMgbp/80fdd26a6b3769a63cdc6b54bf1f39e378545cf7/files/snippet.txt">
|
||||
|
||||
<!-- Naming & Organization -->
|
||||
<shortname>Retrieve ASIE Shard Information/Status</shortname>
|
||||
<family>Inteligr8 ASIE</family>
|
||||
<description><![CDATA[
|
||||
<p>Retrieve meta-data about the specified ASIE shard registered with ACS.</p>
|
||||
<p>The following path and query parameters are expected or supported:</p>
|
||||
<dl>
|
||||
<dt>shardSet</dt>
|
||||
<dd>A shard method combined with its distinguishing properties;
|
||||
methods: MOD_ACL_ID, ACL_ID, DB_ID, DB_ID_RANGE, DATE, PROPERTY, EXPLICIT_ID;
|
||||
e.g. PROPERTY;key:cm:created;regex:^d{4} or DB_ID</dd>
|
||||
<dt>shardId</dt>
|
||||
<dd>A number starting at 1</dd>
|
||||
<dt>sampleHashType</dt>
|
||||
<dd>A sample hash type; Sample hash types: PropertyYear, PropertyQuarter, PropertyMonth, PropertyWeek</dd>
|
||||
</dl>
|
||||
<p>The response will have the following format:</p>
|
||||
<pre>{
|
||||
"id": number,
|
||||
"txsCompleted": number,
|
||||
"txsRemaining": number,
|
||||
"latestTx": "datetime",
|
||||
"nodes": {
|
||||
"string": { // ASIE node URL
|
||||
"url": "string",
|
||||
"hostname": "string"
|
||||
},
|
||||
...
|
||||
},
|
||||
"shardSet": {
|
||||
"id": "string", // generated shard set ID
|
||||
"method": "string",
|
||||
"methodDetail": "string",
|
||||
"hasContent": boolean,
|
||||
"shardCount": number,
|
||||
"shardHashSamples": {
|
||||
"string": [ // shard ID as string
|
||||
"string": // year as string
|
||||
],
|
||||
...
|
||||
}
|
||||
}
|
||||
}</pre>
|
||||
<p>The following status codes should be expected:</p>
|
||||
<dl>
|
||||
<dt>200</dt>
|
||||
<dd>OK</dd>
|
||||
<dt>204</dt>
|
||||
<dd>No ASIE shard information available</dd>
|
||||
<dt>400</dt>
|
||||
<dd>The parameters are invalid</dd>
|
||||
<dt>404</dt>
|
||||
<dd>The specified shard set or shard ID could not be found</dd>
|
||||
</dl>
|
||||
]]></description>
|
||||
|
||||
<!-- Endpoint Configuration -->
|
||||
<url>/inteligr8/asie/shard/{shardSet}/{shardId}?includeSampleHashes={includeSampleHashes?}</url>
|
||||
<format default="json">any</format>
|
||||
|
||||
<!-- Security -->
|
||||
<authentication>admin</authentication>
|
||||
|
||||
<!-- Functionality -->
|
||||
<cache>
|
||||
<never>false</never>
|
||||
<public>false</public>
|
||||
</cache>
|
||||
|
||||
</webscript>
|
@@ -0,0 +1,68 @@
|
||||
<webscript xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://bitbucket.org/!api/2.0/snippets/inteligr8/AzMgbp/80fdd26a6b3769a63cdc6b54bf1f39e378545cf7/files/snippet.txt">
|
||||
|
||||
<!-- Naming & Organization -->
|
||||
<shortname>Retrieve ASIE Shard Information/Status</shortname>
|
||||
<family>Inteligr8 ASIE</family>
|
||||
<description><![CDATA[
|
||||
<p>Retrieve meta-data about all the ASIE shards registered with ACS.</p>
|
||||
<p>The following query parameter is supported:</p>
|
||||
<dl>
|
||||
<dt>sampleHashType</dt>
|
||||
<dd>A sample hash type; Sample hash types: PropertyYear, PropertyQuarter, PropertyMonth, PropertyWeek</dd>
|
||||
</dl>
|
||||
<p>The response will have the following format:</p>
|
||||
<pre>{
|
||||
"string": { // generated shard set ID
|
||||
"methodSpec": "string", // generated shard set ID
|
||||
"shardCount": number
|
||||
"shards": {
|
||||
"string": { // shard ID as string
|
||||
"id": number,
|
||||
"txsCompleted": number,
|
||||
"txsRemaining": number,
|
||||
"latestTx": "datetime",
|
||||
"nodes": {
|
||||
"string": { // ASIE node URL
|
||||
"id": "string",
|
||||
"txsCompleted": number,
|
||||
"latestTx": "datetime",
|
||||
},
|
||||
...
|
||||
}
|
||||
},
|
||||
...
|
||||
},
|
||||
"shardHashSamples": {
|
||||
"string": [ // shard ID as string
|
||||
"string": // year as string
|
||||
],
|
||||
...
|
||||
}
|
||||
}
|
||||
}</pre>
|
||||
<p>The following status codes should be expected:</p>
|
||||
<dl>
|
||||
<dt>200</dt>
|
||||
<dd>OK</dd>
|
||||
<dt>204</dt>
|
||||
<dd>No ASIE shard information available</dd>
|
||||
<dt>400</dt>
|
||||
<dd>The query parameter is invalid</dd>
|
||||
</dl>
|
||||
]]></description>
|
||||
|
||||
<!-- Endpoint Configuration -->
|
||||
<url>/inteligr8/asie/shards?sampleHashType={sampleHashType?}</url>
|
||||
<format default="json">any</format>
|
||||
|
||||
<!-- Security -->
|
||||
<authentication>admin</authentication>
|
||||
|
||||
<!-- Functionality -->
|
||||
<cache>
|
||||
<never>false</never>
|
||||
<public>false</public>
|
||||
</cache>
|
||||
|
||||
</webscript>
|
@@ -0,0 +1,8 @@
|
||||
|
||||
# defaulting to 3 days = 60 * 24 * 3 = 4320
|
||||
inteligr8.asie.backup.persistTimeMinutes=4320
|
||||
|
||||
inteligr8.asie.allowedAuthorities=ALFRESCO_ADMINISTRATORS
|
||||
|
||||
# same as solr.baseUrl, but that property is private to the Search subsystem
|
||||
inteligr8.asie.basePath=/solr
|
@@ -0,0 +1,3 @@
|
||||
|
||||
logger.inteligr8-asie.name=com.inteligr8.alfresco.asie
|
||||
logger.inteligr8-asie.level=INFO
|
@@ -0,0 +1,24 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
|
||||
<!-- Use this file for beans to be loaded in whatever order Alfresco/Spring decides -->
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
|
||||
|
||||
<!-- Enable Spring annotation scanning for classes -->
|
||||
<context:component-scan base-package="com.inteligr8.alfresco.asie"
|
||||
name-generator="org.springframework.context.annotation.FullyQualifiedAnnotationBeanNameGenerator" />
|
||||
|
||||
<bean id="search.ShardRegistry" class="org.alfresco.repo.management.subsystems.SubsystemProxyFactory">
|
||||
<property name="sourceApplicationContextFactory" ref="Search" />
|
||||
<property name="sourceBeanName" value="search.SolrShardRegistry" />
|
||||
<property name="interfaces">
|
||||
<list>
|
||||
<value>org.alfresco.repo.index.shard.ShardRegistry</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
@@ -0,0 +1,10 @@
|
||||
module.id=com_inteligr8_alfresco_${project.artifactId}
|
||||
module.aliases=
|
||||
module.title=${project.name}
|
||||
module.description=${project.description}
|
||||
module.version=${module.version}
|
||||
|
||||
module.repo.version.min=23.0
|
||||
|
||||
# this is creating all sorts of problems; probably because of the non-standard versioning
|
||||
module.depends.com.inteligr8.alfresco.cxf-jaxrs-platform-module=*
|
54
pom.xml
Normal file
54
pom.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.inteligr8.alfresco</groupId>
|
||||
<artifactId>asie-platform-module-parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>ASIE Platform Module Parent</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<maven.compiler.release>11</maven.compiler.release>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<!-- avoids log4j dependency -->
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.13.0</version>
|
||||
</plugin>
|
||||
<!-- avoids struts dependency -->
|
||||
<plugin>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>3.12.1</version>
|
||||
</plugin>
|
||||
<!-- Force use of a new maven-dependency-plugin that doesn't download struts dependency -->
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>3.8.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
<modules>
|
||||
<module>solr-api</module>
|
||||
<module>asie-api</module>
|
||||
<module>module</module>
|
||||
</modules>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>alfresco-private</id>
|
||||
<url>https://artifacts.alfresco.com/nexus/content/groups/private</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
</project>
|
1
solr-api/.gitignore
vendored
Normal file
1
solr-api/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target/
|
79
solr-api/pom.xml
Normal file
79
solr-api/pom.xml
Normal file
@@ -0,0 +1,79 @@
|
||||
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.inteligr8</groupId>
|
||||
<artifactId>solr-api</artifactId>
|
||||
<version>1.0-SNAPSHOT-solr6</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Apache Solr JAX-RS API</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<maven.compiler.release>11</maven.compiler.release>
|
||||
|
||||
<jackson.version>2.18.0</jackson.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>jakarta.annotation</groupId>
|
||||
<artifactId>jakarta.annotation-api</artifactId>
|
||||
<version>2.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.ws.rs</groupId>
|
||||
<artifactId>jakarta.ws.rs-api</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.module</groupId>
|
||||
<artifactId>jackson-module-jaxb-annotations</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.jakarta.rs</groupId>
|
||||
<artifactId>jackson-jakarta-rs-json-provider</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Including for testing purposes only -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>5.11.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<!-- avoids log4j dependency -->
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.13.0</version>
|
||||
</plugin>
|
||||
<!-- avoids struts dependency -->
|
||||
<plugin>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>3.12.1</version>
|
||||
</plugin>
|
||||
<!-- Force use of a new maven-dependency-plugin that doesn't download struts dependency -->
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>3.7.1</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
@@ -0,0 +1,26 @@
|
||||
package com.inteligr8.solr.api;
|
||||
|
||||
import com.inteligr8.solr.model.ActionResponse;
|
||||
import com.inteligr8.solr.model.ResponseAction;
|
||||
import com.inteligr8.solr.model.collection.AliasesResponse;
|
||||
import com.inteligr8.solr.model.collection.GetAliasesRequest;
|
||||
import com.inteligr8.solr.model.core.ReloadRequest;
|
||||
|
||||
import jakarta.ws.rs.BeanParam;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
|
||||
@Path("admin/collections")
|
||||
public interface CollectionAdminApi {
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
ActionResponse<ResponseAction> reload(@BeanParam ReloadRequest request);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
AliasesResponse getAliases(@BeanParam GetAliasesRequest request);
|
||||
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
package com.inteligr8.solr.api;
|
||||
|
||||
import com.inteligr8.solr.model.EmptyResponse;
|
||||
import com.inteligr8.solr.model.core.CreateRequest;
|
||||
import com.inteligr8.solr.model.core.ReloadRequest;
|
||||
import com.inteligr8.solr.model.core.RenameRequest;
|
||||
import com.inteligr8.solr.model.core.RequestStatusRequest;
|
||||
import com.inteligr8.solr.model.core.RequestStatusResponse;
|
||||
import com.inteligr8.solr.model.core.StatusRequest;
|
||||
import com.inteligr8.solr.model.core.StatusResponse;
|
||||
import com.inteligr8.solr.model.core.SwapRequest;
|
||||
import com.inteligr8.solr.model.core.UnloadRequest;
|
||||
|
||||
import jakarta.ws.rs.BeanParam;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
|
||||
@Path("admin/cores")
|
||||
public interface CoreAdminApi {
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
StatusResponse getStatus(@BeanParam StatusRequest request);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
EmptyResponse create(@BeanParam CreateRequest request);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
EmptyResponse reload(@BeanParam ReloadRequest request);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
EmptyResponse rename(@BeanParam RenameRequest request);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
EmptyResponse swap(@BeanParam SwapRequest request);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
EmptyResponse unload(@BeanParam UnloadRequest request);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
RequestStatusResponse getRequestStatus(@BeanParam RequestStatusRequest request);
|
||||
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
package com.inteligr8.solr.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty.Access;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ActionResponse<T extends ResponseAction> extends BaseResponse {
|
||||
|
||||
@JsonProperty(access = Access.READ_ONLY)
|
||||
private T action;
|
||||
|
||||
public T getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
protected void setAction(T action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user