001/* 002 * Copyright 2016 Anyware Services 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 */ 016package org.ametys.cms.content.indexing.solr; 017 018import java.io.IOException; 019import java.util.ArrayList; 020import java.util.Date; 021import java.util.List; 022 023import org.apache.avalon.framework.component.Component; 024import org.apache.avalon.framework.service.ServiceException; 025import org.apache.avalon.framework.service.ServiceManager; 026import org.apache.avalon.framework.service.Serviceable; 027import org.apache.solr.client.solrj.SolrClient; 028import org.apache.solr.client.solrj.SolrServerException; 029import org.apache.solr.client.solrj.response.UpdateResponse; 030import org.apache.solr.client.solrj.util.ClientUtils; 031import org.apache.solr.common.SolrInputDocument; 032 033import org.ametys.cms.search.solr.SolrClientProvider; 034import org.ametys.plugins.repository.AmetysObject; 035import org.ametys.plugins.workflow.repository.WorkflowAwareAmetysObject; 036import org.ametys.plugins.workflow.support.WorkflowProvider; 037import org.ametys.plugins.workflow.support.WorkflowProvider.AmetysObjectWorkflow; 038import org.ametys.runtime.plugin.component.AbstractLogEnabled; 039 040import com.opensymphony.workflow.spi.Step; 041 042/** 043 * Component indexing the whole workflow of {@link AmetysObject}s. 044 */ 045public class SolrWorkflowIndexer extends AbstractLogEnabled implements Component, Serviceable, SolrFieldNames 046{ 047 /** The component role. */ 048 public static final String ROLE = SolrWorkflowIndexer.class.getName(); 049 050 /** The Solr client provider */ 051 protected SolrClientProvider _solrClientProvider; 052 053 /** The workflow provider. */ 054 protected WorkflowProvider _workflowProvider; 055 056 @Override 057 public void service(ServiceManager serviceManager) throws ServiceException 058 { 059 _solrClientProvider = (SolrClientProvider) serviceManager.lookup(SolrClientProvider.ROLE); 060 _workflowProvider = (WorkflowProvider) serviceManager.lookup(WorkflowProvider.ROLE); 061 } 062 063 /** 064 * Index the workflow history of an Ametys object. 065 * @param object The ametys object. 066 * @param workspaceName The workspace where to work in 067 * @throws SolrServerException If a solr error occurs. 068 * @throws IOException If an I/O error occurs while indexing. 069 */ 070 public void indexAmetysObjectWorkflow(WorkflowAwareAmetysObject object, String workspaceName) throws SolrServerException, IOException 071 { 072 SolrClient solrClient = _solrClientProvider.getUpdateClient(workspaceName, true); 073 indexAmetysObjectWorkflow(object, workspaceName, solrClient); 074 } 075 076 /** 077 * Index the workflow history of an Ametys object. 078 * @param object The ametys object. 079 * @param workspaceName The workspace where to work in 080 * @param solrClient The solr client to use 081 * @throws SolrServerException If a solr error occurs. 082 * @throws IOException If an I/O error occurs while indexing. 083 */ 084 public void indexAmetysObjectWorkflow(WorkflowAwareAmetysObject object, String workspaceName, SolrClient solrClient) throws SolrServerException, IOException 085 { 086 long time_0 = System.currentTimeMillis(); 087 getLogger().debug("Indexing the workflow of {}", object); 088 089 AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(object); 090 091 long workflowId = object.getWorkflowId(); 092 List<Step> currentSteps = workflow.getCurrentSteps(workflowId); 093 List<Step> historySteps = workflow.getHistorySteps(workflowId); 094 095 String objectId = object.getId(); 096 097 List<SolrInputDocument> documents = new ArrayList<>(); 098 099 List<String> historyStepIds = indexSteps(historySteps, objectId, documents); 100 List<String> currentStepIds = indexSteps(currentSteps, objectId, documents); 101 102 indexWorkflowEntry(workflow, workflowId, objectId, historyStepIds, currentStepIds, documents); 103 104 String collection = _solrClientProvider.getCollectionName(workspaceName); 105 UpdateResponse solrResponse = solrClient.add(collection, documents); 106 int status = solrResponse.getStatus(); 107 108 if (status != 0) 109 { 110 throw new IOException("Workflow history indexation error (status code=" + status + ")"); 111 } 112 113 getLogger().debug("Successfully indexed workflow of {} in {} ms", object, System.currentTimeMillis() - time_0); 114 } 115 116 private void indexWorkflowEntry(AmetysObjectWorkflow workflow, long workflowId, String objectId, List<String> historyStepIds, List<String> currentStepIds, List<SolrInputDocument> documents) 117 { 118 SolrInputDocument entryDoc = new SolrInputDocument(); 119 120 String id = objectId + "#workflow"; 121 122 String name = workflow.getWorkflowName(workflowId); 123 int state = workflow.getEntryState(workflowId); 124 125 entryDoc.addField(ID, id); 126 entryDoc.addField(DOCUMENT_TYPE, TYPE_WF_ENTRY); 127 entryDoc.addField(WORKFLOW_NAME, name); 128 entryDoc.addField(WORKFLOW_ENTRY_STATE, state); 129 entryDoc.addField(WORKFLOW_HISTORY_STEPS_DV, historyStepIds); 130 entryDoc.addField(WORKFLOW_CURRENT_STEPS_DV, currentStepIds); 131 132 documents.add(entryDoc); 133 } 134 135 private List<String> indexSteps(List<Step> steps, String objectId, List<SolrInputDocument> documents) 136 { 137 List<String> ids = new ArrayList<>(); 138 139 for (Step step : steps) 140 { 141 String id = indexStep(step, objectId, documents); 142 ids.add(id); 143 } 144 145 return ids; 146 } 147 148 private String indexStep(Step step, String objectId, List<SolrInputDocument> documents) 149 { 150 SolrInputDocument entryDoc = new SolrInputDocument(); 151 152 String id = objectId + "#step" + step.getId(); 153 int stepId = step.getStepId(); 154 int actionId = step.getActionId(); 155 String owner = step.getOwner(); 156 String caller = step.getCaller(); 157 Date startDate = step.getStartDate(); 158 Date dueDate = step.getDueDate(); 159 Date finishDate = step.getFinishDate(); 160 String status = step.getStatus(); 161 162 entryDoc.addField(ID, id); 163 entryDoc.addField(DOCUMENT_TYPE, TYPE_WF_STEP); 164 165 entryDoc.addField(WORKFLOW_STEP_ID, stepId); 166 entryDoc.addField(WORKFLOW_STEP_ACTIONID, actionId); 167 if (owner != null) 168 { 169 entryDoc.addField(WORKFLOW_STEP_OWNER, owner); 170 } 171 if (caller != null) 172 { 173 entryDoc.addField(WORKFLOW_STEP_CALLER, caller); 174 } 175 if (startDate != null) 176 { 177 entryDoc.addField(WORKFLOW_STEP_STARTDATE, startDate); 178 } 179 if (dueDate != null) 180 { 181 entryDoc.addField(WORKFLOW_STEP_DUEDATE, dueDate); 182 } 183 if (finishDate != null) 184 { 185 entryDoc.addField(WORKFLOW_STEP_FINISHDATE, finishDate); 186 } 187 if (status != null) 188 { 189 entryDoc.addField(WORKFLOW_STEP_STATUS, status); 190 } 191 192 documents.add(entryDoc); 193 194 return id; 195 } 196 197 /** 198 * Unindex the workflow history of an Ametys object. 199 * @param objectId The Ametys object ID. 200 * @param workspaceName The workspace where to work in 201 * @param solrClient The solr client to use 202 * @throws SolrServerException If a solr error occurs. 203 * @throws IOException If an I/O error occurs while indexing. 204 */ 205 public void unindexAmetysObjectWorkflow(String objectId, String workspaceName, SolrClient solrClient) throws SolrServerException, IOException 206 { 207 // _documentType:(workflowEntry OR workflowStep) AND id:content\://xxx#* 208 StringBuilder query = new StringBuilder(); 209 query.append(DOCUMENT_TYPE).append(":(") 210 .append(TYPE_WF_ENTRY).append(" OR ").append(TYPE_WF_STEP) 211 .append(") AND id:").append(ClientUtils.escapeQueryChars(objectId + "#")).append("*"); 212 213 solrClient.deleteByQuery(_solrClientProvider.getCollectionName(workspaceName), query.toString()); 214 } 215 216}