/*
* Copyright (c) 2010-2016 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.gui.api.util;
import java.util.*;
import com.evolveum.midpoint.prism.query.ObjectPaging;
import com.evolveum.midpoint.prism.query.OrderDirection;
import com.evolveum.midpoint.schema.RelationalValueSearchQuery;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.task.api.TaskManager;
import com.evolveum.midpoint.web.page.login.PageLogin;
import com.evolveum.midpoint.web.security.MidPointApplication;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import org.apache.commons.lang.LocaleUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import com.evolveum.midpoint.gui.api.page.PageBase;
import com.evolveum.midpoint.model.api.ModelExecuteOptions;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.PrismObjectDefinition;
import com.evolveum.midpoint.prism.delta.ChangeType;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.schema.GetOperationOptions;
import com.evolveum.midpoint.schema.RetrieveOption;
import com.evolveum.midpoint.schema.SelectorOptions;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.ObjectTypeUtil;
import com.evolveum.midpoint.security.api.MidPointPrincipal;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.exception.AuthorizationException;
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.ObjectAlreadyExistsException;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.PolicyViolationException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SecurityViolationException;
import com.evolveum.midpoint.util.logging.LoggingUtils;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.web.security.SecurityUtils;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.Session;
import org.jetbrains.annotations.Nullable;
/**
* Utility class that contains methods that interact with ModelService and other
* midPoint components.
*
* @author lazyman
*/
public class WebModelServiceUtils {
private static final Trace LOGGER = TraceManager.getTrace(WebModelServiceUtils.class);
private static final String DOT_CLASS = WebModelServiceUtils.class.getName() + ".";
private static final String OPERATION_LOAD_OBJECT = DOT_CLASS + "loadObject";
private static final String OPERATION_DELETE_OBJECT = DOT_CLASS + "deleteObject";
private static final String OPERATION_SEARCH_OBJECTS = DOT_CLASS + "searchObjects";
private static final String OPERATION_SAVE_OBJECT = DOT_CLASS + "saveObject";
private static final String OPERATION_LOAD_OBJECT_REFS = DOT_CLASS + "loadObjectReferences";
private static final String OPERATION_COUNT_OBJECT = DOT_CLASS + "countObjects";
public static String resolveReferenceName(ObjectReferenceType ref, PageBase page) {
Task task = page.createSimpleTask(WebModelServiceUtils.class.getName() + ".resolveReferenceName");
return resolveReferenceName(ref, page, task, task.getResult());
}
public static String resolveReferenceName(ObjectReferenceType ref, PageBase page, Task task, OperationResult result) {
if (ref == null) {
return null;
}
if (ref.getTargetName() != null) {
return ref.getTargetName().getOrig();
}
PrismObject<ObjectType> object = resolveReferenceRaw(ref, page, task, result);
if (object == null) {
return ref.getOid();
} else {
ref.asReferenceValue().setObject(object);
return WebComponentUtil.getName(object);
}
}
public static <T extends ObjectType> PrismObject<T> resolveReferenceRaw(ObjectReferenceType reference, PageBase page, Task task, OperationResult result) {
if (reference == null) {
return null;
}
if (reference.asReferenceValue().getObject() != null) {
return reference.asReferenceValue().getObject();
}
PrismContext prismContext = page.getPrismContext();
if (reference.getType() == null) {
LOGGER.error("No type in {}", reference);
return null;
}
PrismObjectDefinition<T> definition = prismContext.getSchemaRegistry().findObjectDefinitionByType(reference.getType());
if (definition == null) {
LOGGER.error("No definition for {} was found", reference.getType());
return null;
}
return loadObject(definition.getCompileTimeClass(), reference.getOid(),
SelectorOptions.createCollection(GetOperationOptions.createRaw()), page, task, result);
}
public static <O extends ObjectType> List<ObjectReferenceType> createObjectReferenceList(Class<O> type, PageBase page, Map<String, String> referenceMap){
referenceMap.clear();
OperationResult result = new OperationResult(OPERATION_LOAD_OBJECT_REFS);
// Task task = page.createSimpleTask(OPERATION_LOAD_PASSWORD_POLICIES);
try{
List<PrismObject<O>> objects = searchObjects(type, null, result, page);
result.recomputeStatus();
if(objects != null){
List<ObjectReferenceType> references = new ArrayList<>();
for(PrismObject<O> object: objects){
referenceMap.put(object.getOid(), WebComponentUtil.getName(object));
references.add(ObjectTypeUtil.createObjectRef(object));
}
return references;
}
} catch (Exception e){
result.recordFatalError("Couldn't load password policies.", e);
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't load password policies", e);
}
// TODO - show error somehow
// if(!result.isSuccess()){
// getPageBase().showResult(result);
// }
return null;
}
public static String runTask(TaskType taskToRun, Task operationalTask, OperationResult parentResult, PageBase pageBase){
try {
ObjectDelta<TaskType> delta = ObjectDelta.createAddDelta(taskToRun.asPrismObject());
pageBase.getPrismContext().adopt(delta);
pageBase.getModelService().executeChanges(WebComponentUtil.createDeltaCollection(delta), null,
operationalTask, parentResult);
parentResult.recordInProgress();
parentResult.setBackgroundTaskOid(delta.getOid());
pageBase.showResult(parentResult);
return delta.getOid();
} catch (ObjectAlreadyExistsException | ObjectNotFoundException | SchemaException
| ExpressionEvaluationException | CommunicationException | ConfigurationException
| PolicyViolationException | SecurityViolationException e) {
// TODO Auto-generated catch block
// error(pageBase.getString("pageUsers.message.nothingSelected") + e.getMessage());
parentResult.recordFatalError("Couldn't run task " + e.getMessage(), e);
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't run task " + e.getMessage(), e);
return null;
}
}
public static void runTask(Collection<TaskType> tasksToRun, Task operationalTask, OperationResult parentResult, PageBase pageBase){
// try {
for (TaskType taskToRun : tasksToRun){
runTask(tasksToRun, operationalTask, parentResult, pageBase);
}
// }
// ObjectDelta<TaskType> delta = ObjectDelta.createAddDelta(taskToRun.asPrismObject());
// pageBase.getPrismContext().adopt(delta);
// pageBase.getModelService().executeChanges(WebComponentUtil.createDeltaCollection(delta), null,
// operationalTask, parentResult);
// parentResult.recordInProgress();
// parentResult.setBackgroundTaskOid(delta.getOid());
// pageBase.showResult(parentResult);
// return delta.getOid();
// } catch (ObjectAlreadyExistsException | ObjectNotFoundException | SchemaException
// | ExpressionEvaluationException | CommunicationException | ConfigurationException
// | PolicyViolationException | SecurityViolationException e) {
// // TODO Auto-generated catch block
//// error(pageBase.getString("pageUsers.message.nothingSelected") + e.getMessage());
// parentResult.recordFatalError("Couldn't run task " + e.getMessage(), e);
// LoggingUtils.logUnexpectedException(LOGGER, "Couldn't run task " + e.getMessage(), e);
// return null;
// }
}
@Nullable
public static <T extends ObjectType> PrismObject<T> loadObject(Class<T> type, String oid,
PageBase page, Task task, OperationResult result) {
return loadObject(type, oid, null, page, task, result);
}
@Nullable
public static <T extends ObjectType> PrismObject<T> loadObject(Class<T> type, String oid,
Collection<SelectorOptions<GetOperationOptions>> options,
PageBase page, Task task, OperationResult result) {
return loadObject(type, oid, options, true, page, task, result);
}
@Nullable
public static <T extends ObjectType> PrismObject<T> loadObject(Class<T> type, String oid,
Collection<SelectorOptions<GetOperationOptions>> options, boolean allowNotFound,
PageBase page, Task task, OperationResult result) {
LOGGER.debug("Loading {} with oid {}, options {}", type.getSimpleName(), oid, options);
OperationResult subResult;
if (result != null) {
subResult = result.createMinorSubresult(OPERATION_LOAD_OBJECT);
} else {
subResult = new OperationResult(OPERATION_LOAD_OBJECT);
}
PrismObject<T> object = null;
try {
if (options == null) {
options = SelectorOptions.createCollection(GetOperationOptions.createResolveNames());
} else {
GetOperationOptions getOpts = SelectorOptions.findRootOptions(options);
if (getOpts == null) {
options.add(new SelectorOptions<>(GetOperationOptions.createResolveNames()));
} else {
getOpts.setResolveNames(Boolean.TRUE);
}
}
object = page.getModelService().getObject(type, oid, options, task, subResult);
} catch (AuthorizationException e) {
// Not authorized to access the object. This is probably caused by a reference that
// point to an object that the current user cannot read. This is no big deal.
// Just do not display that object.
subResult.recordHandledError(e);
LOGGER.debug("User {} is not authorized to read {} {}",
task.getOwner() != null ? task.getOwner().getName() : null, type.getSimpleName(), oid);
return null;
} catch (ObjectNotFoundException e) {
if (allowNotFound) {
// Object does not exist. It was deleted in the meanwhile, or not created yet. This could happen quite often.
subResult.recordHandledError(e);
LOGGER.debug("{} {} does not exist", type.getSimpleName(), oid, e);
return null;
} else {
subResult.recordFatalError("WebModelUtils.couldntLoadObject", e);
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't load object", e);
}
} catch (Exception ex) {
subResult.recordFatalError("WebModelUtils.couldntLoadObject", ex);
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't load object", ex);
} finally {
subResult.computeStatus();
}
// TODO reconsider this part: until recently, the condition was always 'false'
if (WebComponentUtil.showResultInPage(subResult)) {
page.showResult(subResult);
}
LOGGER.debug("Loaded {} with result {}", object, subResult);
return object;
}
public static boolean isNoFetch(Collection<SelectorOptions<GetOperationOptions>> options) {
if (options == null) {
return false;
}
GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options);
if (rootOptions == null) {
return false;
}
return GetOperationOptions.isNoFetch(rootOptions);
}
public static <T extends ObjectType> List<PrismObject<T>> searchObjects(Class<T> type, ObjectQuery query,
OperationResult result, PageBase page) {
return searchObjects(type, query, null, result, page, null);
}
public static <T extends ObjectType> List<PrismObject<T>> searchObjects(Class<T> type, ObjectQuery query,
Collection<SelectorOptions<GetOperationOptions>> options,
OperationResult result, PageBase page) {
return searchObjects(type, query, options, result, page, null);
}
public static <T extends ObjectType> List<PrismObject<T>> searchObjects(Class<T> type, ObjectQuery query,
Collection<SelectorOptions<GetOperationOptions>> options,
OperationResult result, PageBase page,
PrismObject<UserType> principal) {
LOGGER.debug("Searching {} with oid {}, options {}", new Object[]{type.getSimpleName(), query, options});
OperationResult subResult;
if (result != null) {
subResult = result.createMinorSubresult(OPERATION_SEARCH_OBJECTS);
} else {
subResult = new OperationResult(OPERATION_SEARCH_OBJECTS);
}
List<PrismObject<T>> objects = new ArrayList<PrismObject<T>>();
try {
Task task = createSimpleTask(subResult.getOperation(), principal, page.getTaskManager());
List<PrismObject<T>> list = page.getModelService().searchObjects(type, query, options, task, subResult);
if (list != null) {
objects.addAll(list);
}
} catch (Exception ex) {
subResult.recordFatalError("WebModelUtils.couldntSearchObjects", ex);
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't search objects", ex);
} finally {
subResult.computeStatus();
}
if (result == null && WebComponentUtil.showResultInPage(subResult)) {
page.showResult(subResult);
}
LOGGER.debug("Loaded ({}) with result {}", new Object[]{objects.size(), subResult});
return objects;
}
public static <T extends ObjectType> int countObjects(Class<T> type, ObjectQuery query, PageBase page) {
LOGGER.debug("Count object: type => {}, query => {}", type, query);
Task task = page.createSimpleTask(OPERATION_COUNT_OBJECT);
OperationResult parentResult = new OperationResult(OPERATION_COUNT_OBJECT);
int count = 0;
try {
count = page.getModelService().countObjects(type, query, null, task, parentResult);
} catch (SchemaException | ObjectNotFoundException | SecurityViolationException
| ConfigurationException | CommunicationException ex) {
parentResult.recordFatalError("WebModelUtils.couldntCountObjects", ex);
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't count objects", ex);
}
LOGGER.debug("Count objects with result {}", new Object[]{parentResult});
return count;
}
public static <T extends ObjectType> void deleteObject(Class<T> type, String oid, OperationResult result,
PageBase page) {
deleteObject(type, oid, null, result, page, null);
}
public static <T extends ObjectType> void deleteObject(Class<T> type, String oid, ModelExecuteOptions options,
OperationResult result, PageBase page) {
deleteObject(type, oid, options, result, page, null);
}
public static <T extends ObjectType> void deleteObject(Class<T> type, String oid, ModelExecuteOptions options,
OperationResult result, PageBase page,
PrismObject<UserType> principal) {
LOGGER.debug("Deleting {} with oid {}, options {}", new Object[]{type.getSimpleName(), oid, options});
OperationResult subResult;
if (result != null) {
subResult = result.createMinorSubresult(OPERATION_DELETE_OBJECT);
} else {
subResult = new OperationResult(OPERATION_DELETE_OBJECT);
}
try {
Task task = createSimpleTask(result.getOperation(), principal, page.getTaskManager());
ObjectDelta delta = new ObjectDelta(type, ChangeType.DELETE, page.getPrismContext());
delta.setOid(oid);
page.getModelService().executeChanges(WebComponentUtil.createDeltaCollection(delta), options, task, subResult);
} catch (Exception ex) {
subResult.recordFatalError("WebModelUtils.couldntDeleteObject", ex);
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't delete object", ex);
} finally {
subResult.computeStatus();
}
if (result == null && WebComponentUtil.showResultInPage(subResult)) {
page.showResult(subResult);
}
LOGGER.debug("Deleted with result {}", new Object[]{result});
}
public static Collection<SelectorOptions<GetOperationOptions>> createOptionsForParentOrgRefs() {
Collection<SelectorOptions<GetOperationOptions>> options = new ArrayList<SelectorOptions<GetOperationOptions>>();
options.add(SelectorOptions.create(ObjectType.F_PARENT_ORG_REF,
GetOperationOptions.createRetrieve(RetrieveOption.INCLUDE)));
return options;
}
public static Collection<SelectorOptions<GetOperationOptions>> createMinimalOptions() {
Collection<SelectorOptions<GetOperationOptions>> options = new ArrayList<>();
options.add(SelectorOptions.create(ItemPath.EMPTY_PATH,
GetOperationOptions.createRetrieve(RetrieveOption.DEFAULT)));
return options;
}
public static void save(ObjectDelta delta, OperationResult result, PageBase page) {
save(delta, result, null, page);
}
public static void save(ObjectDelta delta, OperationResult result, Task task, PageBase page) {
save(delta, null, result, task, page);
}
public static void save(ObjectDelta delta, ModelExecuteOptions options, OperationResult result, Task task, PageBase page) {
save(WebComponentUtil.createDeltaCollection(delta), options, result, task, page);
}
public static void save(Collection<ObjectDelta<? extends ObjectType>> deltas, ModelExecuteOptions options,
OperationResult result, Task task, PageBase page) {
LOGGER.debug("Saving deltas {}, options {}", new Object[]{deltas, options});
OperationResult subResult;
if (result != null) {
subResult = result.createMinorSubresult(OPERATION_SAVE_OBJECT);
} else {
subResult = new OperationResult(OPERATION_SAVE_OBJECT);
}
try {
if (task == null) {
task = page.createSimpleTask(result.getOperation());
}
page.getModelService().executeChanges(deltas, options, task, result);
} catch (Exception ex) {
subResult.recordFatalError(ex.getMessage());
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't save object", ex);
} finally {
subResult.computeStatus();
}
if (result == null && WebComponentUtil.showResultInPage(subResult)) {
page.showResult(subResult);
}
LOGGER.debug("Saved with result {}", new Object[]{subResult});
}
public static <T extends ObjectType> ObjectDelta<T> createActivationAdminStatusDelta(
Class<T> type, String oid, boolean enabled, PrismContext context) {
ItemPath path = new ItemPath(FocusType.F_ACTIVATION, ActivationType.F_ADMINISTRATIVE_STATUS);
ActivationStatusType status = enabled ? ActivationStatusType.ENABLED : ActivationStatusType.DISABLED;
ObjectDelta objectDelta = ObjectDelta.createModificationReplaceProperty(type, oid, path, context, status);
return objectDelta;
}
public static String getLoggedInUserOid() {
MidPointPrincipal principal = SecurityUtils.getPrincipalUser();
Validate.notNull(principal, "No principal");
if (principal.getOid() == null) {
throw new IllegalArgumentException("No OID in principal: "+principal);
}
return principal.getOid();
}
public static Locale getLocale() {
return getLocale(null);
}
public static Locale getLocale(UserType user) {
MidPointPrincipal principal = SecurityUtils.getPrincipalUser();
Locale locale = null;
if (principal != null) {
if (user == null) {
PrismObject<UserType> userPrismObject = principal.getUser().asPrismObject();
user = userPrismObject == null ? null : userPrismObject.asObjectable();
}
if (user != null && user.getPreferredLanguage() != null &&
!user.getPreferredLanguage().trim().equals("")) {
try {
locale = LocaleUtils.toLocale(user.getPreferredLanguage());
} catch (Exception ex) {
LOGGER.debug("Error occurred while getting user locale, " + ex.getMessage());
}
}
if (locale != null && MidPointApplication.containsLocale(locale)) {
return locale;
} else {
String userLocale = user != null ? user.getLocale() : null;
try {
locale = userLocale == null ? null : LocaleUtils.toLocale(userLocale);
} catch (Exception ex) {
LOGGER.debug("Error occurred while getting user locale, " + ex.getMessage());
}
if (locale != null && MidPointApplication.containsLocale(locale)) {
return locale;
} else {
locale = Session.get().getLocale();
if (locale == null || !MidPointApplication.containsLocale(locale)) {
//default locale for web application
return MidPointApplication.getDefaultLocale();
}
return locale;
}
}
}
return null;
}
public static TimeZone getTimezone() {
return getTimezone(null);
}
public static TimeZone getTimezone(UserType user) {
MidPointPrincipal principal = SecurityUtils.getPrincipalUser();
if (principal != null && user == null) {
user = principal.getUser();
}
String timeZone;
if (user != null && StringUtils.isNotEmpty(user.getTimezone())) {
timeZone = user.getTimezone();
} else {
timeZone = principal != null && principal.getAdminGuiConfiguration() != null ?
principal.getAdminGuiConfiguration().getDefaultTimezone() : "";
}
try {
if (timeZone != null) {
return TimeZone.getTimeZone(timeZone);
}
} catch (Exception ex){
LOGGER.debug("Error occurred while getting user time zone, " + ex.getMessage());
}
return null;
}
public static Task createSimpleTask(String operation, PrismObject<UserType> owner, TaskManager manager) {
Task task = manager.createTaskInstance(operation);
if (owner == null) {
MidPointPrincipal user = SecurityUtils.getPrincipalUser();
if (user == null) {
throw new RestartResponseException(PageLogin.class);
} else {
owner = user.getUser().asPrismObject();
}
}
task.setOwner(owner);
task.setChannel(SchemaConstants.CHANNEL_GUI_USER_URI);
return task;
}
public static <O extends ObjectType> PrismObject<O> reconstructObject(Class<O> type,
String oid, String eventIdentifier, Task task, OperationResult result){
try {
MidPointApplication application = (MidPointApplication) MidPointApplication.get();
return application.getAuditService().reconstructObject(type, oid, eventIdentifier, task, result);
} catch (Exception ex){
LOGGER.debug("Error occurred while reconsructing the object, " + ex.getMessage());
}
return null;
}
public static Collection<SelectorOptions<GetOperationOptions>> createLookupTableRetrieveOptions() {
return SelectorOptions.createCollection(LookupTableType.F_ROW,
GetOperationOptions.createRetrieve(
new RelationalValueSearchQuery(
ObjectPaging.createPaging(LookupTableRowType.F_LABEL, OrderDirection.ASCENDING))));
}
}