/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.jackrabbit.core.security.user;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.jcr.ImportUUIDBehavior;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.nodetype.ConstraintViolationException;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.api.security.principal.PrincipalIterator;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.Group;
import org.apache.jackrabbit.api.security.user.Impersonation;
import org.apache.jackrabbit.api.security.user.User;
import org.apache.jackrabbit.api.security.user.UserManager;
import org.apache.jackrabbit.commons.flat.PropertySequence;
import org.apache.jackrabbit.core.NodeImpl;
import org.apache.jackrabbit.core.SessionImpl;
import org.apache.jackrabbit.core.id.NodeId;
import org.apache.jackrabbit.core.security.principal.PrincipalImpl;
import org.apache.jackrabbit.core.session.SessionContext;
import org.apache.jackrabbit.core.session.SessionWriteOperation;
import org.apache.jackrabbit.core.state.NodeState;
import org.apache.jackrabbit.core.util.ReferenceChangeTracker;
import org.apache.jackrabbit.core.xml.NodeInfo;
import org.apache.jackrabbit.core.xml.PropInfo;
import org.apache.jackrabbit.core.xml.ProtectedNodeImporter;
import org.apache.jackrabbit.core.xml.ProtectedPropertyImporter;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.QPropertyDefinition;
import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* <code>UserImporter</code> implements a <code>DefaultProtectedPropertyImporter</code>
* and <code>DefaultProtectedNodeImporter</code> that is able to deal with
* user/group content as defined by the default user related node types present
* with jackrabbit-core.<p/>
*
* The importer is intended to be used by applications that import user content
* extracted from another repository instance and immediately persist the
* imported content using {@link javax.jcr.Session#save()}. Omitting the
* save call will lead to transient, semi-validated user content and eventually
* to inconsistencies.
* <p/>
* Note the following restrictions:
* <ul>
* <li>The importer will only be initialized if the user manager is an instance
* of <code>UserPerWorkspaceUserManager</code>.
* </li>
* <li>The importer will only be initialized if the editing session starting
* this import is the same as the UserManager's Session instance.
* </li>
* <li>The jcr:uuid property of user and groups is defined to represent the
* hashed authorizable id as calculated by the UserManager. This importer
* is therefore not able to handle imports with
* {@link ImportUUIDBehavior#IMPORT_UUID_CREATE_NEW}.</li>
* <li>Importing user/group nodes outside of the hierarchy defined by
* {@link org.apache.jackrabbit.core.security.user.UserManagerImpl#getUsersPath()}
* and {@link org.apache.jackrabbit.core.security.user.UserManagerImpl#getGroupsPath()}
* will fail upon save as the mandatory properties will not be imported. The same may
* be true in case of {@link ImportUUIDBehavior#IMPORT_UUID_COLLISION_REPLACE_EXISTING}
* inserting the user/group node at some other place in the node hierarchy.</li>
* <li>While creating user/groups through the API the <code>UserManagerImpl</code> makes
* sure that authorizables are never nested and are created below a hierarchy
* of nt:AuthorizableFolder nodes. This isn't enforced by means of node type
* constraints but only by the API. This importer currently doesn't perform such
* a validation check.</li>
* <li>Any attempt to import conflicting data will cause the import to fail
* either immediately or upon calling {@link javax.jcr.Session#save()} with the
* following exceptions:
* <ul>
* <li><code>rep:members</code> : Group membership</li>
* <li><code>rep:impersonators</code> : Impersonators of a User.</li>
* </ul>
* The import behavior of these two properties is defined by the {@link #PARAM_IMPORT_BEHAVIOR}
* configuration parameter, which can be set to
* <ul>
* <li>{@link ImportBehavior#NAME_IGNORE ignore}: A warning is logged.</li>
* <li>{@link ImportBehavior#NAME_BESTEFFORT best effort}: A warning is logged
* and the importer tries to fix the problem.</li>
* <li>{@link ImportBehavior#NAME_ABORT abort}: The import is immediately
* aborted with a ConstraintViolationException. (<strong>default</strong>)</li>
* </ul>
* </li>
* </ul>
* Known Issue:<br>
* Importing <code>rep:impersonators</code> property referring to principals
* that are created during this import AND have principalName different from the
* ID will no succeed, as the validation in <code>ImpersonationImpl</code> isn't able
* to find the authorizable with the given principal (reason: query will only
* find persisted content).
*/
public class UserImporter implements ProtectedPropertyImporter, ProtectedNodeImporter {
private static final Logger log = LoggerFactory.getLogger(UserImporter.class);
/**
* Parameter name for the import behavior configuration option.
*/
public static final String PARAM_IMPORT_BEHAVIOR = "importBehavior";
private JackrabbitSession session;
private NamePathResolver resolver;
private ReferenceChangeTracker referenceTracker;
private UserPerWorkspaceUserManager userManager;
private boolean initialized = false;
private boolean resetAutoSave = false;
private int importBehavior = ImportBehavior.IGNORE;
/**
* Container used to collect group members stored in protected nodes.
*/
private Membership currentMembership;
/**
* Temporary store for the pw an imported new user to be able to call
* the creation actions irrespective of the order of protected properties
*/
private Map<String,String> currentPw = new HashMap<String,String>(1);
public boolean init(JackrabbitSession session, NamePathResolver resolver,
boolean isWorkspaceImport,
int uuidBehavior, ReferenceChangeTracker referenceTracker) {
this.session = session;
this.resolver = resolver;
this.referenceTracker = referenceTracker;
if (initialized) {
throw new IllegalStateException("Already initialized");
}
if (uuidBehavior == ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW) {
log.debug("ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW isn't supported when importing users or groups.");
return false;
}
if (isWorkspaceImport) {
log.debug("Only Session-Import is supported when importing users or groups.");
return false;
}
try {
UserManager uMgr = session.getUserManager();
if (uMgr instanceof UserPerWorkspaceUserManager) {
// make sure the user managers autosave flag can be changed to false.
if (uMgr.isAutoSave()) {
uMgr.autoSave(false);
resetAutoSave = true;
log.debug("Changed autosave behavior of UserManager to 'false'.");
}
userManager = (UserPerWorkspaceUserManager) uMgr;
initialized = true;
} else {
// either wrong implementation or one that implicitly calls save.
log.debug("Failed to initialize UserImporter: UserManager isn't instance of UserPerWorkspaceUserManager or does implicit save call.");
}
} catch (RepositoryException e) {
// failed to access user manager or to set the autosave behavior
// -> return false (not initialized) as importer can't operate.
log.error("Failed to initialize UserImporter: ", e);
}
return initialized;
}
// -----------------------------------------< ProtectedPropertyImporter >---
/**
* @see ProtectedPropertyImporter#handlePropInfo(org.apache.jackrabbit.core.NodeImpl, org.apache.jackrabbit.core.xml.PropInfo, org.apache.jackrabbit.spi.QPropertyDefinition)
*/
public boolean handlePropInfo(NodeImpl parent, PropInfo protectedPropInfo, QPropertyDefinition def) throws RepositoryException {
if (!initialized) {
throw new IllegalStateException("Not initialized");
}
/* importer can only handle protected properties below user/group
nodes that are properly stored underneath the configured users/groups
hierarchies (see {@link UserManagerImpl#getAuthorizable(NodeImpl)}.
this prevents from importing user/group nodes somewhere in the
content hierarchy which isn't possible when creating user/groups
using the corresponding API calls {@link UserManager#createUser} or
{@link UserManager#createGroup} respectively. */
Authorizable a = userManager.getAuthorizable(parent);
if (a == null) {
log.warn("Cannot handle protected PropInfo " + protectedPropInfo + ". Node " + parent + " doesn't represent a valid Authorizable.");
return false;
}
// TODO: check if import should be aborted in case of nested authorizable.
// assert that user manager is isn't in auto-save mode
if (userManager.isAutoSave()) {
userManager.autoSave(false);
}
try {
Name propName = protectedPropInfo.getName();
if (UserConstants.P_PRINCIPAL_NAME.equals(propName)) {
// minimal validation that passed definition really matches the
// protected rep:principalName property defined by rep:Authorizable.
if (def.isMultiple() || !UserConstants.NT_REP_AUTHORIZABLE.equals(def.getDeclaringNodeType())) {
// some other unexpected property definition -> cannot handle
log.warn("Unexpected definition for property rep:principalName");
return false;
}
Value v = protectedPropInfo.getValues(PropertyType.STRING, resolver)[0];
String princName = v.getString();
userManager.setPrincipal(parent, new PrincipalImpl(princName));
/*
Execute authorizable actions for a NEW group as this is the
same place in the userManager#createGroup that the actions
are called.
In case of a NEW user the actions are executed if the password
has been imported before.
*/
if (parent.isNew()) {
if (a.isGroup()) {
userManager.onCreate((Group) a);
} else if (currentPw.containsKey(a.getID())) {
userManager.onCreate((User) a, currentPw.remove(a.getID()));
}
}
return true;
} else if (UserConstants.P_PASSWORD.equals(propName)) {
if (a.isGroup()) {
log.warn("Expected parent node of type rep:User.");
return false;
}
// minimal validation of the passed definition
if (def.isMultiple() || !UserConstants.NT_REP_USER.equals(def.getDeclaringNodeType())) {
// some other unexpected property definition -> cannot handle
log.warn("Unexpected definition for property rep:password");
return false;
}
Value v = protectedPropInfo.getValues(PropertyType.STRING, resolver)[0];
String pw = v.getString();
userManager.setPassword(parent, pw, false);
/*
Execute authorizable actions for a NEW user at this point after
having set the password if the principal name has already been
processed, otherwise postpone it.
*/
if (parent.isNew()) {
if (parent.hasProperty(UserConstants.P_PRINCIPAL_NAME)) {
userManager.onCreate((User) a, pw);
} else {
// principal name not yet available -> remember the pw
currentPw.clear();
currentPw.put(a.getID(), pw);
}
}
return true;
} else if (UserConstants.P_IMPERSONATORS.equals(propName)) {
if (a.isGroup()) {
// unexpected parent type -> cannot handle
log.warn("Expected parent node of type rep:User.");
return false;
}
// minimal validation of the passed definition
if (!def.isMultiple() || !UserConstants.MIX_REP_IMPERSONATABLE.equals(def.getDeclaringNodeType())) {
// some other unexpected property definition -> cannot handle
log.warn("Unexpected definition for property rep:impersonators");
return false;
}
// since impersonators may be imported later on, postpone processing
// to the end.
// see -> process References
Value[] vs = protectedPropInfo.getValues(PropertyType.STRING, resolver);
referenceTracker.processedReference(new Impersonators(a.getID(), vs));
return true;
} else if (UserConstants.P_DISABLED.equals(propName)) {
if (a.isGroup()) {
log.warn("Expected parent node of type rep:User.");
return false;
}
// minimal validation of the passed definition
if (def.isMultiple() || !UserConstants.NT_REP_USER.equals(def.getDeclaringNodeType())) {
// some other unexpected property definition -> cannot handle
log.warn("Unexpected definition for property rep:disabled");
return false;
}
Value v = protectedPropInfo.getValues(PropertyType.STRING, resolver)[0];
((User) a).disable(v.getString());
return true;
} else if (UserConstants.P_MEMBERS.equals(propName)) {
if (!a.isGroup()) {
// unexpected parent type -> cannot handle
log.warn("Expected parent node of type rep:Group.");
return false;
}
// minimal validation of the passed definition
if (!def.isMultiple() || !UserConstants.NT_REP_GROUP.equals(def.getDeclaringNodeType())) {
// some other unexpected property definition -> cannot handle
log.warn("Unexpected definition for property rep:members");
return false;
}
// since group-members are references to user/groups that potentially
// are to be imported later on -> postpone processing to the end.
// see -> process References
Membership membership = new Membership(a.getID());
for (Value v : protectedPropInfo.getValues(PropertyType.WEAKREFERENCE, resolver)) {
membership.addMember(new NodeId(v.getString()));
}
referenceTracker.processedReference(membership);
return true;
} // else: cannot handle -> return false
return false;
} finally {
// reset the autosave mode of the user manager in order to restore
// the original state.
if (resetAutoSave) {
userManager.autoSave(true);
}
}
}
/**
* @see ProtectedPropertyImporter#handlePropInfo(org.apache.jackrabbit.core.NodeImpl, org.apache.jackrabbit.core.xml.PropInfo, org.apache.jackrabbit.spi.QPropertyDefinition)
*/
public boolean handlePropInfo(NodeState parent, PropInfo protectedPropInfo, QPropertyDefinition def) throws RepositoryException {
return false;
}
/**
* @see org.apache.jackrabbit.core.xml.ProtectedPropertyImporter#processReferences()
*/
public void processReferences() throws RepositoryException {
if (!initialized) {
throw new IllegalStateException("Not initialized");
}
// assert that user manager is isn't in auto-save mode
if (userManager.isAutoSave()) {
userManager.autoSave(false);
}
try {
List<Object> processed = new ArrayList<Object>();
for (Iterator<Object> it = referenceTracker.getProcessedReferences(); it.hasNext();) {
Object reference = it.next();
if (reference instanceof Membership) {
Authorizable a = userManager.getAuthorizable(((Membership) reference).groupId);
if (a == null || !a.isGroup()) {
throw new RepositoryException(((Membership) reference).groupId + " does not represent a valid group.");
}
final Group gr = (Group) a;
// 1. collect members to add and to remove.
Map<String, Authorizable> toRemove = new HashMap<String, Authorizable>();
for (Iterator<Authorizable> declMembers = gr.getDeclaredMembers(); declMembers.hasNext();) {
Authorizable dm = declMembers.next();
toRemove.put(dm.getID(), dm);
}
List<Authorizable> toAdd = new ArrayList<Authorizable>();
final List<Membership.Member> nonExisting = new ArrayList<Membership.Member>();
for (Membership.Member member : ((Membership) reference).members) {
NodeId remapped = referenceTracker.getMappedId(member.id);
NodeId id = (remapped == null) ? member.id : remapped;
Authorizable authorz = null;
try {
NodeImpl n = ((SessionImpl) session).getNodeById(id);
authorz = userManager.getAuthorizable(n);
} catch (RepositoryException e) {
// no such node or failed to retrieve authorizable
// warning is logged below.
}
if (authorz != null) {
if (toRemove.remove(authorz.getID()) == null) {
toAdd.add(authorz);
} // else: no need to remove from rep:members
} else {
handleFailure("New member of " + gr + ": No such authorizable (NodeID = " + id + ")");
if (importBehavior == ImportBehavior.BESTEFFORT) {
log.info("ImportBehavior.BESTEFFORT: Remember non-existing member for processing.");
nonExisting.add(member);
}
}
}
// 2. adjust members of the group
for (Authorizable m : toRemove.values()) {
if (!gr.removeMember(m)) {
handleFailure("Failed remove existing member (" + m + ") from " + gr);
}
}
for (Authorizable m : toAdd) {
if (!gr.addMember(m)) {
handleFailure("Failed add member (" + m + ") to " + gr);
}
}
// handling non-existing members in case of best-effort
if (!nonExisting.isEmpty()) {
log.info("ImportBehavior.BESTEFFORT: Found " + nonExisting.size() + " entries of rep:members pointing to non-existing authorizables. Adding to rep:members.");
final NodeImpl groupNode = ((AuthorizableImpl) gr).getNode();
if (userManager.hasMemberSplitSize()) {
userManager.performProtectedOperation((SessionImpl) session, new SessionWriteOperation<Object>() {
public Boolean perform(SessionContext context) throws RepositoryException {
NodeImpl nMembers = (groupNode.hasNode(UserConstants.N_MEMBERS)
? groupNode.getNode(UserConstants.N_MEMBERS)
: groupNode.addNode(UserConstants.N_MEMBERS, UserConstants.NT_REP_MEMBERS, null));
// Create N_MEMBERS node structure for holding member references
for (Membership.Member member : nonExisting) {
PropertySequence properties = GroupImpl.getPropertySequence(nMembers, userManager);
String propName = member.name;
if (propName == null) {
log.debug("Ignoring unnamed user with id {}", member.id);
continue;
}
if (properties.hasItem(propName)) {
log.debug("Overwriting authorizable {} which is already member of {}.", propName, gr);
properties.removeProperty(propName);
}
Value newMember = session.getValueFactory().createValue(member.id.toString(), PropertyType.WEAKREFERENCE);
properties.addProperty(propName, newMember);
}
return null;
}
});
} else {
// Create P_MEMBERS for holding member references
// build list of valid members set before ....
List<Value> memberValues = new ArrayList<Value>();
if (groupNode.hasProperty(UserConstants.P_MEMBERS)) {
Value[] vls = groupNode.getProperty(UserConstants.P_MEMBERS).getValues();
memberValues.addAll(Arrays.asList(vls));
}
// ... and the non-Existing ones.
for (Membership.Member member : nonExisting) {
memberValues.add(session.getValueFactory().createValue(member.id.toString(), PropertyType.WEAKREFERENCE));
}
// and use implementation specific method to set the
// value of rep:members properties which was not possible
// through the API
userManager.setProtectedProperty(groupNode,
UserConstants.P_MEMBERS,
memberValues.toArray(new Value[memberValues.size()]),
PropertyType.WEAKREFERENCE);
}
}
processed.add(reference);
} else if (reference instanceof Impersonators) {
Authorizable a = userManager.getAuthorizable(((Impersonators) reference).userId);
if (a == null || a.isGroup()) {
throw new RepositoryException(((Impersonators) reference).userId + " does not represent a valid user.");
}
Impersonation imp = ((User) a).getImpersonation();
// 1. collect principals to add and to remove.
Map<String, Principal> toRemove = new HashMap<String, Principal>();
for (PrincipalIterator pit = imp.getImpersonators(); pit.hasNext();) {
Principal princ = pit.nextPrincipal();
toRemove.put(princ.getName(), princ);
}
List<Principal> toAdd = new ArrayList<Principal>();
Value[] vs = ((Impersonators) reference).values;
for (Value v : vs) {
String princName = v.getString();
if (toRemove.remove(princName) == null) {
// add it to the list of new impersonators to be added.
toAdd.add(new PrincipalImpl(princName));
} // else: no need to revoke impersonation for the given principal.
}
// 2. adjust set of impersonators
for (Principal princ : toRemove.values()) {
if (!imp.revokeImpersonation(princ)) {
handleFailure("Failed to revoke impersonation for " + princ.getName() + " on " + a);
}
}
for (Principal princ : toAdd) {
if (!imp.grantImpersonation(princ)) {
handleFailure("Failed to grant impersonation for " + princ.getName() + " on " + a);
}
}
// NOTE: no best effort handling so far. (TODO)
processed.add(reference);
}
}
// successfully processed this entry of the reference tracker
// -> remove from the reference tracker.
referenceTracker.removeReferences(processed);
} finally {
// reset the autosave mode of the user manager in order to restore
// the original state.
if (resetAutoSave) {
userManager.autoSave(true);
}
}
}
// ---------------------------------------------< ProtectedNodeImporter >---
/**
* @see ProtectedNodeImporter#start(org.apache.jackrabbit.core.NodeImpl)
*/
public boolean start(NodeImpl protectedParent) throws RepositoryException {
String repMembers = resolver.getJCRName(UserConstants.NT_REP_MEMBERS);
if (repMembers.equals(protectedParent.getPrimaryNodeType().getName())) {
NodeImpl groupNode = protectedParent;
while(groupNode.getDepth() != 0 &&
repMembers.equals(groupNode.getPrimaryNodeType().getName())) {
groupNode = (NodeImpl) groupNode.getParent();
}
Authorizable auth = userManager.getAuthorizable(groupNode);
if (auth == null) {
log.debug("Cannot handle protected node " + protectedParent + ". It nor one of its parents represent a valid Authorizable.");
return false;
}
else {
currentMembership = new Membership(auth.getID());
return true;
}
}
else {
return false;
}
}
/**
* @see ProtectedNodeImporter#start(org.apache.jackrabbit.core.state.NodeState)
*/
public boolean start(NodeState protectedParent) {
return false;
}
/**
* @see ProtectedNodeImporter#start(org.apache.jackrabbit.core.NodeImpl)
*/
public void startChildInfo(NodeInfo childInfo, List<PropInfo> propInfos) throws RepositoryException {
assert (currentMembership != null);
if (UserConstants.NT_REP_MEMBERS.equals(childInfo.getNodeTypeName())) {
for (PropInfo prop : propInfos) {
for (Value v : prop.getValues(PropertyType.WEAKREFERENCE, resolver)) {
String name = resolver.getJCRName(prop.getName());
NodeId id = new NodeId(v.getString());
currentMembership.addMember(name, id);
}
}
}
else {
log.warn("{} is not of type {}", childInfo.getName(), UserConstants.NT_REP_MEMBERS);
}
}
/**
* @see org.apache.jackrabbit.core.xml.ProtectedNodeImporter#endChildInfo()
*/
public void endChildInfo() throws RepositoryException {
}
/**
* @see ProtectedNodeImporter#end(org.apache.jackrabbit.core.NodeImpl)
*/
public void end(NodeImpl protectedParent) throws RepositoryException {
referenceTracker.processedReference(currentMembership);
currentMembership = null;
}
/**
* @see ProtectedNodeImporter#end(org.apache.jackrabbit.core.state.NodeState)
*/
public void end(NodeState protectedParent) {
}
//---------------------------------------------------------< BeanConfig >---
/**
* @return human readable representation of the <code>importBehavior</code> value.
*/
public String getImportBehavior() {
return ImportBehavior.nameFromValue(importBehavior);
}
/**
*
* @param importBehaviorStr
*/
public void setImportBehavior(String importBehaviorStr) {
this.importBehavior = ImportBehavior.valueFromName(importBehaviorStr);
}
//------------------------------------------------------------< private >---
/**
* Handling the import behavior
*
* @param msg
* @throws RepositoryException
*/
private void handleFailure(String msg) throws RepositoryException {
switch (importBehavior) {
case ImportBehavior.IGNORE:
case ImportBehavior.BESTEFFORT:
log.warn(msg);
break;
case ImportBehavior.ABORT:
throw new ConstraintViolationException(msg);
default:
// no other behavior. nothing to do.
}
}
//------------------------------------------------------< inner classes >---
/**
* Inner class used to postpone import of group membership to the very end
* of the import. This allows to import membership of user/groups that
* are only being created during this import.
*
* @see ImportBehavior For additional configuration options.
*/
private static final class Membership {
private final String groupId;
private final List<Member> members = new LinkedList<Member>();
public Membership(String groupId) {
this.groupId = groupId;
}
public void addMember(String name, NodeId id) {
members.add(new Member(name, id));
}
public void addMember(NodeId id) {
addMember(null, id);
}
// If only Java had tuples...
public class Member {
private final String name;
private final NodeId id;
public Member(String name, NodeId id) {
super();
this.name = name;
this.id = id;
}
}
}
/**
* Inner class used to postpone import of impersonators to the very end
* of the import. This allows to import impersonation values pointing
* to user that are only being created during this import.
*
* @see ImportBehavior For additional configuration options.
*/
private static final class Impersonators {
private final String userId;
private final Value[] values;
private Impersonators(String userId, Value[] values) {
this.userId = userId;
this.values = values;
}
}
/**
* Inner class defining the treatment of membership or impersonator
* values pointing to non-existing authorizables.
*/
public static final class ImportBehavior {
/**
* If a member or impersonator value cannot be set due to constraints
* enforced by the API implementation, the failure is logged as
* warning but otherwise ignored.
*/
public static final int IGNORE = 1;
/**
* Same as {@link #IGNORE} but in addition tries to circumvent the
* problem. This option should only be used with validated and trusted
* XML passed to the SessionImporter.
*/
public static final int BESTEFFORT = 2;
/**
* Aborts the import as soon as invalid values are detected throwing
* a <code>ConstraintViolationException</code>.
*/
public static final int ABORT = 3;
public static final String NAME_IGNORE = "ignore";
public static final String NAME_BESTEFFORT = "besteffort";
public static final String NAME_ABORT = "abort";
public static int valueFromName(String behaviorString) {
if (NAME_IGNORE.equalsIgnoreCase(behaviorString)) {
return IGNORE;
} else if (NAME_BESTEFFORT.equalsIgnoreCase(behaviorString)) {
return BESTEFFORT;
} else if (NAME_ABORT.equalsIgnoreCase(behaviorString)) {
return ABORT;
} else {
log.error("Invalid behavior " + behaviorString + " -> Using default: ABORT.");
return ABORT;
}
}
public static String nameFromValue(int importBehavior) {
switch (importBehavior) {
case ImportBehavior.IGNORE:
return NAME_IGNORE;
case ImportBehavior.ABORT:
return NAME_ABORT;
case ImportBehavior.BESTEFFORT:
return NAME_BESTEFFORT;
default:
throw new IllegalArgumentException("Invalid import behavior: " + importBehavior);
}
}
}
}