/******************************************************************************* * Copyright (c) 2009-2015, G. Weirich and Elexis * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * G. Weirich - initial implementation * MEDEVIT <office@medevit.at> - major refactorings #2112 *******************************************************************************/ package ch.elexis.admin; import java.io.Serializable; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ch.elexis.core.data.activator.CoreHub; import ch.elexis.core.data.constants.ExtensionPointConstantsData; import ch.elexis.core.data.util.Extensions; import ch.elexis.core.jdt.NonNull; import ch.elexis.core.jdt.Nullable; import ch.elexis.data.Query; import ch.elexis.data.Right; import ch.elexis.data.Role; /** * AcessControlElement * * An item constituting a named right. AccessControlElements are collected hierarchically in ACL's * (AccessControlLists). An ACE has a parent, an internal name and a (probably localized) external * name that will be shown to the user. <br> * <br> * ACEs are loaded within {@link AbstractAccessControl#load()} * * @since 2.0 * @author gerry * */ public class ACE implements Serializable { private static final long serialVersionUID = 34320020090119L; public static final String ACE_ROOT_LITERAL = "root";//$NON-NLS-1$ public static final ACE ACE_ROOT = new ACE(null, ACE_ROOT_LITERAL, Messages.ACE_root); public static final ACE ACE_IMPLICIT = new ACE(ACE.ACE_ROOT, "implicit", Messages.ACE_implicit); //$NON-NLS-1$ private static Map<String, ACE> allDefinedACEs; private static Logger log = LoggerFactory.getLogger(ACE.class); private final String name; private String localizedName; private final ACE parent; private List<ACE> children = new ArrayList<ACE>(); /** * initialize all defined ACEs, only performed once * * @return */ private static void initAllDefinedACEs(){ if (allDefinedACEs != null) return; List<ACE> temp = getACLContributionExtensions().stream() .flatMap(acl -> Arrays.asList(acl.getACL()).stream()).collect(Collectors.toList()); allDefinedACEs = temp.stream().collect(Collectors.toMap(a -> a.getCanonicalName(), a -> a)); } /** * initialize the default ACE values * * @param reset * resets all configured rights before installing the defaults * @since 3.1 */ public static void initializeACEDefaults(boolean reset){ if (reset) { Query<Role> arq = new Query<Role>(Role.class); List<Role> allRoles = arq.execute(); for (Role role : allRoles) { role.revokeAllRightsForRole(); } Right.resetTable(); } List<IACLContributor> aclContributionExtensions = getACLContributionExtensions(); for (IACLContributor iaclContributor : aclContributionExtensions) { try { iaclContributor.initializeDefaults(CoreHub.acl); } catch (Exception e) { log.warn("Problem initializing defaults for [{}]", iaclContributor.getClass().getName(), e); } } } @SuppressWarnings("unchecked") private static List<IACLContributor> getACLContributionExtensions(){ return Extensions.getClasses(ExtensionPointConstantsData.ACL_CONTRIBUTION, ExtensionPointConstantsData.ACL_CONTRIBUTION_PT_CONTRIBUTOR); } /** * Create a new ACE. This is the recommended constructor for most cases. * * @param parent * the parent ACE. If this is a top-level ACE, use {@link #ACE_ROOT} as parent. * @param name * the internal, immutable name of this ACE. Should be unique. Therefore, it is * recommended to prefix the name with the plugin ID * @param localizedName * the name that will be presented to the user. This should be a translatable String */ public ACE(ACE parent, String name, String localizedName){ this.parent = parent; this.name = name; this.localizedName = localizedName; if (parent != null) parent.addChild(this); } private void addChild(ACE ace){ children.add(ace); } /** * create a new ACE without localized name. The localized name will be the same as the internal * name. So this constructor should <b>not</b> be used for ACE's that will be shown to the user. * * @param parent * the parent ACE. If this is a top-evel ACE, use ACE_ROOT as parent. * @param name * the internal, immutable name of this ACE. Should be unique. Therefore, it is * recommended to prefix the name with the plugin ID. */ public ACE(ACE parent, String name){ this(parent, name, name); } /** * @return the non-translatable name of this ACE */ public String getName(){ return name; } /** * @return the localized Name of this ACE */ public String getLocalizedName(){ return localizedName; } /** * @return the parent ACE */ public ACE getParent(){ return parent; } /** * @param deep * recurse to bottom, or <code>false</code> deliver direct children * @return a list of all children to this, in unspecific order, including self * @since 3.1 */ public List<ACE> getChildren(boolean deep){ if (deep) { return getChildrenRecursive(); } else { return new ArrayList<ACE>(children); } } /** * recursively fetch all children, adding self * * @return */ private List<ACE> getChildrenRecursive(){ List<ACE> ret = new ArrayList<ACE>(); ret.add(this); for (ACE ace : children) { ret.addAll(ace.getChildrenRecursive()); } return ret; } /** * Change the localized name of this ACE * * @param lName * a new name to use as localized name */ public void setLocalizedName(String lName){ localizedName = lName; } /** * get the full pathname of an ACE. This Method is internal to the ACL system and should not be * used externally */ String getCanonicalName(){ StringBuilder sp = new StringBuilder(); sp.append(getName()); ACE parent = getParent(); while ((parent != null) && (!parent.equals(ACE.ACE_ROOT))) { sp.insert(0, parent.getName() + "/"); //$NON-NLS-1$ parent = parent.getParent(); } return sp.toString(); } /** * @return a unique hex string for the ACE that is derived by its canonical name and name, if * {@link #ACE_ROOT} returns <code>root</code> * @since 3.1 */ public String getUniqueHashFromACE(){ if (ACE_ROOT.equals(this)) return ACE_ROOT_LITERAL; int valCan = Math.abs(getCanonicalName().hashCode()); int valNam = Math.abs(getName().hashCode()); BigInteger valI = new BigInteger(valCan + "" + valNam); return valI.toString(16); } /** * @return all defined ACE elements * @since 3.1 */ public static @NonNull List<ACE> getAllDefinedACElements(){ initAllDefinedACEs(); return new ArrayList<ACE>(allDefinedACEs.values()); } /** * @return the root elements of all ACElements * @since 3.1 */ public static @NonNull ACE[] getAllDefinedRootACElements(){ return ACE.getAllDefinedACElements().stream() .filter(p -> ACE.ACE_ROOT.equals(p.getParent())).toArray(size -> new ACE[size]); } /** * @return this element and its entire parent chain */ public List<ACE> getParentChainIncludingSelf(){ List<ACE> aces = new ArrayList<ACE>(); aces.add(this); if (this.equals(ACE_ROOT)) return aces; ACE parent = getParent(); while (parent != ACE_ROOT) { aces.add(parent); parent = parent.getParent(); } return aces; } @Override public String toString(){ return getUniqueHashFromACE() + " " + getName() + " " + getCanonicalName(); } /** * @param uniqueHash * @return */ public static @Nullable ACE getACEByCanonicalName(String canonicalName){ initAllDefinedACEs(); return allDefinedACEs.get(canonicalName); } }