001/* 002 * (C) Copyright 2018 Nuxeo (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Kevin Leturc <[email protected]> 018 */ 019package org.nuxeo.ecm.core.bulk.message; 020 021import static org.apache.commons.lang3.StringUtils.isEmpty; 022 023import java.io.Serializable; 024import java.util.Collections; 025import java.util.HashMap; 026import java.util.Map; 027import java.util.UUID; 028 029import org.apache.avro.reflect.AvroEncode; 030import org.apache.avro.reflect.Nullable; 031import org.apache.commons.lang3.builder.EqualsBuilder; 032import org.apache.commons.lang3.builder.HashCodeBuilder; 033import org.apache.commons.lang3.builder.ToStringBuilder; 034 035/** 036 * A message representing a bulk command 037 * 038 * @since 10.2 039 */ 040public class BulkCommand implements Serializable { 041 042 private static final long serialVersionUID = 20181021L; 043 044 protected String id; 045 046 protected String action; 047 048 protected String query; 049 050 @Nullable 051 protected String username; 052 053 @Nullable 054 protected String repository; 055 056 protected int bucketSize; 057 058 protected int batchSize; 059 060 @AvroEncode(using = MapAsJsonAsStringEncoding.class) 061 protected Map<String, Serializable> params; 062 063 protected BulkCommand() { 064 // Empty constructor for Avro decoder 065 } 066 067 public BulkCommand(Builder builder) { 068 this.id = UUID.randomUUID().toString(); 069 this.username = builder.username; 070 this.repository = builder.repository; 071 this.query = builder.query; 072 this.action = builder.action; 073 this.bucketSize = builder.bucketSize; 074 this.batchSize = builder.batchSize; 075 this.params = builder.params; 076 } 077 078 public String getUsername() { 079 return username; 080 } 081 082 public String getRepository() { 083 return repository; 084 } 085 086 public String getQuery() { 087 return query; 088 } 089 090 public String getAction() { 091 return action; 092 } 093 094 public Map<String, Serializable> getParams() { 095 return Collections.unmodifiableMap(params); 096 } 097 098 @SuppressWarnings("unchecked") 099 public <T> T getParam(String key) { 100 return (T) params.get(key); 101 } 102 103 public String getId() { 104 return id; 105 } 106 107 public int getBucketSize() { 108 return bucketSize; 109 } 110 111 public int getBatchSize() { 112 return batchSize; 113 } 114 115 @Override 116 public int hashCode() { 117 return HashCodeBuilder.reflectionHashCode(this); 118 } 119 120 @Override 121 public boolean equals(Object o) { 122 return EqualsBuilder.reflectionEquals(this, o); 123 } 124 125 @Override 126 public String toString() { 127 return ToStringBuilder.reflectionToString(this); 128 } 129 130 public void setBatchSize(int batchSize) { 131 this.batchSize = batchSize; 132 } 133 134 public void setBucketSize(int bucketSize) { 135 this.bucketSize = bucketSize; 136 } 137 138 public void setRepository(String repository) { 139 this.repository = repository; 140 } 141 142 public static class Builder { 143 protected final String action; 144 145 protected final String query; 146 147 protected String repository; 148 149 protected String username; 150 151 protected int bucketSize; 152 153 protected int batchSize; 154 155 protected Map<String, Serializable> params = new HashMap<>(); 156 157 /** 158 * BulkCommand builder 159 * 160 * @param action the registered bulk action name 161 * @param nxqlQuery the query that represent the document set to apply the action 162 */ 163 public Builder(String action, String nxqlQuery) { 164 if (isEmpty(action)) { 165 throw new IllegalArgumentException("Action cannot be empty"); 166 } 167 this.action = action; 168 if (isEmpty(nxqlQuery)) { 169 throw new IllegalArgumentException("Query cannot be empty"); 170 } 171 this.query = nxqlQuery; 172 } 173 174 /** 175 * Use a non default document repository 176 */ 177 public Builder repository(String name) { 178 this.repository = name; 179 return this; 180 } 181 182 /** 183 * User running the bulk action 184 */ 185 public Builder user(String name) { 186 this.username = name; 187 return this; 188 } 189 190 /** 191 * The size of a bucket of documents id that fits into a record 192 */ 193 public Builder bucket(int size) { 194 if (size <= 0) { 195 throw new IllegalArgumentException("Invalid bucket size must > 0"); 196 } 197 if (batchSize > size) { 198 throw new IllegalArgumentException( 199 String.format("Bucket size: %d must be greater or equals to batch size: %d", size, batchSize)); 200 } 201 this.bucketSize = size; 202 return this; 203 } 204 205 /** 206 * The number of documents processed by action within a transaction 207 */ 208 public Builder batch(int size) { 209 if (size <= 0) { 210 throw new IllegalArgumentException("Invalid batch size must > 0"); 211 } 212 if (bucketSize > 0 && size > bucketSize) { 213 throw new IllegalArgumentException( 214 String.format("Bucket size: %d must be greater or equals to batch size: %d", size, batchSize)); 215 } 216 this.batchSize = size; 217 return this; 218 } 219 220 /** 221 * Add an action parameter 222 */ 223 public Builder param(String key, Serializable value) { 224 if (isEmpty(key)) { 225 throw new IllegalArgumentException("Param key cannot be null"); 226 } 227 params.put(key, value); 228 return this; 229 } 230 231 /** 232 * Set all action parameters 233 */ 234 public Builder params(Map<String, Serializable> params) { 235 if (params != null && !params.isEmpty()) { 236 if (params.containsKey(null)) { 237 throw new IllegalArgumentException("Param key cannot be null"); 238 } 239 this.params = params; 240 } 241 return this; 242 } 243 244 public BulkCommand build() { 245 return new BulkCommand(this); 246 } 247 248 } 249}