/* * Copyright (c) 2010-2017 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.evolveum.midpoint.report.impl; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.xml.namespace.QName; import com.evolveum.midpoint.prism.Containerable; import com.evolveum.midpoint.prism.PrismContainerValue; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.evolveum.midpoint.audit.api.AuditEventRecord; import com.evolveum.midpoint.audit.api.AuditService; import com.evolveum.midpoint.model.api.ModelService; import com.evolveum.midpoint.model.common.expression.ExpressionFactory; import com.evolveum.midpoint.model.common.expression.ExpressionUtil; import com.evolveum.midpoint.model.common.expression.ExpressionVariables; import com.evolveum.midpoint.model.common.expression.functions.FunctionLibrary; import com.evolveum.midpoint.model.common.expression.script.jsr223.Jsr223ScriptEvaluator; import com.evolveum.midpoint.model.impl.expr.ExpressionEnvironment; import com.evolveum.midpoint.model.impl.expr.ModelExpressionThreadLocalHolder; import com.evolveum.midpoint.prism.Objectable; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismPropertyValue; import com.evolveum.midpoint.prism.marshaller.QueryConvertor; import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.prism.query.TypeFilter; import com.evolveum.midpoint.report.api.ReportService; import com.evolveum.midpoint.schema.GetOperationOptions; import com.evolveum.midpoint.schema.SelectorOptions; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.ObjectResolver; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.task.api.TaskManager; import com.evolveum.midpoint.util.exception.CommunicationException; import com.evolveum.midpoint.util.exception.ConfigurationException; import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.exception.SecurityViolationException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType; @Component public class ReportServiceImpl implements ReportService { private static final transient Trace LOGGER = TraceManager.getTrace(ReportServiceImpl.class); @Autowired(required = true) private ModelService model; @Autowired(required = true) private TaskManager taskManager; @Autowired(required = true) private PrismContext prismContext; @Autowired(required = true) private ExpressionFactory expressionFactory; @Autowired(required = true) private ObjectResolver objectResolver; @Autowired(required = true) private AuditService auditService; @Autowired(required = true) private FunctionLibrary logFunctionLibrary; @Autowired(required = true) private FunctionLibrary basicFunctionLibrary; @Autowired(required = true) private FunctionLibrary midpointFunctionLibrary; @Override public ObjectQuery parseQuery(String query, Map<QName, Object> parameters) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException { if (StringUtils.isBlank(query)) { return null; } ObjectQuery parsedQuery = null; try { Task task = taskManager.createTaskInstance(); ModelExpressionThreadLocalHolder.pushExpressionEnvironment(new ExpressionEnvironment<>(task, task.getResult())); SearchFilterType filter = prismContext.parserFor(query).parseRealValue(SearchFilterType.class); LOGGER.trace("filter {}", filter); ObjectFilter f = QueryConvertor.parseFilter(filter, UserType.class, prismContext); LOGGER.trace("f {}", f.debugDump()); if (!(f instanceof TypeFilter)) { throw new IllegalArgumentException( "Defined query must contain type. Use 'type filter' in your report query."); } ObjectFilter subFilter = ((TypeFilter) f).getFilter(); ObjectQuery q = ObjectQuery.createObjectQuery(subFilter); ExpressionVariables variables = new ExpressionVariables(); variables.addVariableDefinitions(parameters); q = ExpressionUtil.evaluateQueryExpressions(q, variables, expressionFactory, prismContext, "parsing expression values for report", task, task.getResult()); ((TypeFilter) f).setFilter(q.getFilter()); parsedQuery = ObjectQuery.createObjectQuery(f); LOGGER.trace("query dump {}", parsedQuery.debugDump()); } catch (SchemaException | ObjectNotFoundException | ExpressionEvaluationException e) { // TODO Auto-generated catch block throw e; } finally { ModelExpressionThreadLocalHolder.popExpressionEnvironment(); } return parsedQuery; } @Override public Collection<PrismObject<? extends ObjectType>> searchObjects(ObjectQuery query, Collection<SelectorOptions<GetOperationOptions>> options) throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException { // List<PrismObject<? extends ObjectType>> results = new ArrayList<>(); // GetOperationOptions options = GetOperationOptions.createRaw(); if (!(query.getFilter() instanceof TypeFilter)) { throw new IllegalArgumentException("Query must contain type filter."); } TypeFilter typeFilter = (TypeFilter) query.getFilter(); QName type = typeFilter.getType(); Class clazz = prismContext.getSchemaRegistry().determineCompileTimeClass(type); if (clazz == null) { clazz = prismContext.getSchemaRegistry().findObjectDefinitionByType(type).getCompileTimeClass(); } ObjectQuery queryForSearch = ObjectQuery.createObjectQuery(typeFilter.getFilter()); Task task = taskManager.createTaskInstance(ReportService.class.getName() + ".searchObjects()"); OperationResult parentResult = task.getResult(); // options.add(new // SelectorOptions(GetOperationOptions.createResolveNames())); GetOperationOptions getOptions = GetOperationOptions.createResolveNames(); getOptions.setRaw(Boolean.TRUE); options = SelectorOptions.createCollection(getOptions); List<PrismObject<? extends ObjectType>> results; try { results = model.searchObjects(clazz, queryForSearch, options, task, parentResult); return results; } catch (SchemaException | ObjectNotFoundException | SecurityViolationException | CommunicationException | ConfigurationException e) { // TODO Auto-generated catch block throw e; } } public Collection<PrismContainerValue<? extends Containerable>> evaluateScript(String script, Map<QName, Object> parameters) throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException { List<PrismContainerValue<? extends Containerable>> results = new ArrayList<>(); ExpressionVariables variables = new ExpressionVariables(); variables.addVariableDefinitions(parameters); // special variable for audit report variables.addVariableDefinition(new QName("auditParams"), getConvertedParams(parameters)); Task task = taskManager.createTaskInstance(ReportService.class.getName() + ".evaluateScript"); OperationResult parentResult = task.getResult(); Collection<FunctionLibrary> functions = createFunctionLibraries(); Jsr223ScriptEvaluator scripts = new Jsr223ScriptEvaluator("Groovy", prismContext, prismContext.getDefaultProtector()); ModelExpressionThreadLocalHolder.pushExpressionEnvironment(new ExpressionEnvironment<>(task, task.getResult())); Object o = null; try{ o = scripts.evaluateReportScript(script, variables, objectResolver, functions, "desc", parentResult); } finally{ ModelExpressionThreadLocalHolder.popExpressionEnvironment(); } if (o != null) { if (Collection.class.isAssignableFrom(o.getClass())) { Collection resultSet = (Collection) o; if (resultSet != null && !resultSet.isEmpty()) { for (Object obj : resultSet) { results.add(convertResultingObject(obj)); } } } else { results.add(convertResultingObject(o)); } } return results; } protected PrismContainerValue convertResultingObject(Object obj) { if (obj instanceof PrismObject) { return ((PrismObject) obj).asObjectable().asPrismContainerValue(); } else if (obj instanceof Objectable) { return ((Objectable) obj).asPrismContainerValue(); } else if (obj instanceof PrismContainerValue) { return (PrismContainerValue) obj; } else if (obj instanceof Containerable) { return ((Containerable) obj).asPrismContainerValue(); } else { throw new IllegalStateException("Reporting script should return something compatible with PrismContainerValue, not a " + obj.getClass()); } } public Collection<AuditEventRecord> evaluateAuditScript(String script, Map<QName, Object> parameters) throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException { Collection<AuditEventRecord> results = new ArrayList<AuditEventRecord>(); ExpressionVariables variables = new ExpressionVariables(); variables.addVariableDefinition(new QName("auditParams"), getConvertedParams(parameters)); Task task = taskManager.createTaskInstance(ReportService.class.getName() + ".searchObjects()"); OperationResult parentResult = task.getResult(); Collection<FunctionLibrary> functions = createFunctionLibraries(); Jsr223ScriptEvaluator scripts = new Jsr223ScriptEvaluator("Groovy", prismContext, prismContext.getDefaultProtector()); ModelExpressionThreadLocalHolder.pushExpressionEnvironment(new ExpressionEnvironment<>(task, task.getResult())); Object o = null; try{ o = scripts.evaluateReportScript(script, variables, objectResolver, functions, "desc", parentResult); } finally { ModelExpressionThreadLocalHolder.popExpressionEnvironment(); } if (o != null) { if (Collection.class.isAssignableFrom(o.getClass())) { Collection resultSet = (Collection) o; if (resultSet != null && !resultSet.isEmpty()) { for (Object obj : resultSet) { if (!(obj instanceof AuditEventRecord)) { LOGGER.warn("Skipping result, not an audit event record " + obj); continue; } results.add((AuditEventRecord) obj); } } } else { results.add((AuditEventRecord) o); } } return results; } private Map<String, Object> getConvertedParams(Map<QName, Object> parameters) { if (parameters == null) { return null; } Map<String, Object> resultParams = new HashMap<String, Object>(); Set<Entry<QName, Object>> paramEntries = parameters.entrySet(); for (Entry<QName, Object> e : paramEntries) { if (e.getValue() instanceof PrismPropertyValue) { resultParams.put(e.getKey().getLocalPart(), ((PrismPropertyValue) e.getValue()).getValue()); } else { resultParams.put(e.getKey().getLocalPart(), e.getValue()); } } return resultParams; } private Collection<FunctionLibrary> createFunctionLibraries() { // FunctionLibrary functionLib = ExpressionUtil.createBasicFunctionLibrary(prismContext, // prismContext.getDefaultProtector()); FunctionLibrary midPointLib = new FunctionLibrary(); midPointLib.setVariableName("report"); midPointLib.setNamespace("http://midpoint.evolveum.com/xml/ns/public/function/report-3"); ReportFunctions reportFunctions = new ReportFunctions(prismContext, model, taskManager, auditService); midPointLib.setGenericFunctions(reportFunctions); // // MidpointFunctionsImpl mp = new MidpointFunctionsImpl(); // mp. Collection<FunctionLibrary> functions = new ArrayList<>(); functions.add(basicFunctionLibrary); functions.add(logFunctionLibrary); functions.add(midpointFunctionLibrary); functions.add(midPointLib); return functions; } }