/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.roles.ui.wizard; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.Viewer; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.graphics.Image; import org.teiid.core.designer.ModelerCoreException; import org.teiid.core.designer.util.CoreStringUtil; import org.teiid.core.designer.util.StringConstants; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.container.ContainerImpl; import org.teiid.designer.metamodels.core.ModelAnnotation; import org.teiid.designer.metamodels.core.ModelType; import org.teiid.designer.metamodels.function.ScalarFunction; import org.teiid.designer.metamodels.relational.Catalog; import org.teiid.designer.metamodels.relational.Column; import org.teiid.designer.metamodels.relational.Procedure; import org.teiid.designer.metamodels.relational.ProcedureParameter; import org.teiid.designer.metamodels.relational.ProcedureResult; import org.teiid.designer.metamodels.relational.Schema; import org.teiid.designer.metamodels.relational.Table; import org.teiid.designer.metamodels.relational.View; import org.teiid.designer.metamodels.webservice.Interface; import org.teiid.designer.metamodels.webservice.Operation; import org.teiid.designer.metamodels.xml.XmlDocument; import org.teiid.designer.roles.Crud; import org.teiid.designer.roles.Permission; import org.teiid.designer.roles.ui.Messages; import org.teiid.designer.roles.ui.RolesUiConstants; import org.teiid.designer.roles.ui.RolesUiPlugin; import org.teiid.designer.ui.viewsupport.ModelIdentifier; import org.teiid.designer.ui.viewsupport.ModelUtilities; /** * @since 8.0 */ public class DataRolesModelTreeProvider implements ITreeContentProvider, ITableLabelProvider { private static final Object[] NO_CHILDREN = new Object[0]; private ITreeContentProvider modelProvider = ModelUtilities.getModelContentProvider(); private static final char DELIM = CoreStringUtil.Constants.DOT_CHAR; private static final char B_SLASH = '/'; private static final Image CHECKED_BOX = RolesUiPlugin.getInstance().getAnImage(RolesUiConstants.Images.CHECKED_BOX_ICON); private static final Image UNCHECKED_BOX = RolesUiPlugin.getInstance().getAnImage(RolesUiConstants.Images.UNCHECKED_BOX_ICON); private static final Image GRAY_CHECKED_BOX = RolesUiPlugin.getInstance().getAnImage(RolesUiConstants.Images.GRAY_CHECKED_BOX_ICON); private static final Image GRAY_UNCHECKED_BOX = RolesUiPlugin.getInstance().getAnImage(RolesUiConstants.Images.GRAY_UNCHECKED_BOX_ICON); private static final Image GRAY_STATUS_BOX = RolesUiPlugin.getInstance().getAnImage(RolesUiConstants.Images.GRAY_BALL_ICON); private static final Image WHITE_STATUS_BOX = RolesUiPlugin.getInstance().getAnImage(RolesUiConstants.Images.WHITE_BALL_ICON); private static final Image BLUE_STATUS_BOX = RolesUiPlugin.getInstance().getAnImage(RolesUiConstants.Images.BLUE_BALL_ICON); private static final int CHECKED = 0; private static final int UNCHECKED = 1; private static final int GRAY_CHECKED = 2; private static final int GRAY_UNCHECKED = 3; // private Map<Object, Permission> permissionsMap; private PermissionHandler handler; private Resource[] resources; public DataRolesModelTreeProvider( ) { super(); handler = new PermissionHandler(this); } @Override public void addListener( ILabelProviderListener listener ) { // NO OP } @Override public void dispose() { // NO OP } /* * Helper method to find a check-box image based on boolean value, if it is a parent or not and if it has at lease one * child (or grand-child, etc.) that has a different boolean value. */ private Image getCheckBoxImage(Object element, int columnIndex, Boolean value, boolean isParentValue, boolean hasDifferentChildValue) { // First case where the actual node does not have a CRUD value, so the first parent with a Value determines the state // of the check-box along with the boolean indicating that a child below it has a different value int imageType = CHECKED; if (isParentValue) { if (value == Boolean.FALSE) imageType = GRAY_UNCHECKED; if (hasDifferentChildValue) imageType = GRAY_CHECKED; } // The case where the actual node HAS a Permission with a non-null CRUD value if (value == Boolean.FALSE) imageType = UNCHECKED; if (hasDifferentChildValue) imageType = GRAY_CHECKED; switch(imageType) { case CHECKED: { return CHECKED_BOX; } case UNCHECKED: { return UNCHECKED_BOX; } case GRAY_CHECKED: { return GRAY_CHECKED_BOX; } case GRAY_UNCHECKED: { return GRAY_UNCHECKED_BOX; } default: return null; } } @Override public Object[] getChildren( Object parentElement ) { Object[] children = NO_CHILDREN; if (parentElement instanceof EObject) { children = getFilteredModelContents(modelProvider.getChildren(parentElement)); } else if (parentElement instanceof Resource) { children = getFilteredModelContents(((Resource)parentElement).getContents()); } return children; } @Override public boolean hasChildren( Object parentElement) { return getChildren(parentElement).length > 0; } @Override public Image getColumnImage(Object element, int columnIndex) { if (columnIndex == 0) { return getImage(element); } else if( columnIndex == 1 ) { return getSecurityStatusImage(element); } Crud.Type crudType = Crud.getCrudType(columnIndex); boolean supportsUpdate = handler.supportsUpdates(element, crudType); if (!supportsUpdate) { return GRAY_UNCHECKED_BOX; } // Should ALWAYS FIND ONE if it's a RESOURCE (i.e. Model) Permission perm = handler.getPermission(element); boolean isParent = false; // If no permission exists for this element OR if the element's permission contains a NULL boolean value for this crud type // then we walk up the tree to find the first one that is NON-NULL if (perm == null || perm.getCRUDValue(crudType) == null) { perm = handler.getExistingPermission(element, crudType); isParent = true; } if (perm != null) { Boolean booleanValue = perm.getCRUDValue(crudType); isParent = perm.isPrimary(); boolean hasDifferentChildValue = false; // If the permission is defined by a parent value, then we assume that this element has a NULL value and we need to determine // if any children below the element has a permission crud value not equal to the parent. if (isParent || hasChildren(element) ) { hasDifferentChildValue = handler.hasChildWithDifferentCrudValue(perm, element, crudType); } return getCheckBoxImage(element, columnIndex, booleanValue, isParent, hasDifferentChildValue); } return GRAY_UNCHECKED_BOX; } @Override public String getColumnText(Object element, int columnIndex) { if (columnIndex == 0) { return getText(element); } return null; } @Override public Object[] getElements( Object inputElement ) { if (resources == null) { // Filter out XSD models List<Resource> allVdbResources = ((ContainerImpl)inputElement).getResources(); List<Resource> filteredResources = new ArrayList<Resource>(); for( Resource res : allVdbResources ) { if( ! res.getURI().toFileString().toUpperCase().endsWith(".XSD") ) { //$NON-NLS-1$ filteredResources.add(res); } } resources = filteredResources.toArray( new Resource[0]); } reInitializePermissions(); return resources; } /* * return an array of objects that are filtered for only Relational Model object types. */ private Object[] getFilteredModelContents( List<EObject> eObjs ) { Collection<EObject> relObjects = new ArrayList<EObject>(); for (EObject eObj : eObjs) { if( eObj instanceof Table || eObj instanceof View || eObj instanceof Procedure || eObj instanceof ProcedureResult || eObj instanceof Schema || eObj instanceof Catalog || eObj instanceof Column || eObj instanceof ProcedureParameter || eObj instanceof Interface || eObj instanceof Operation || eObj instanceof XmlDocument || eObj instanceof ScalarFunction) { relObjects.add(eObj); } } return relObjects.toArray(); } /* * return an array of objects that are filtered for only Relational Model object types. */ private Object[] getFilteredModelContents( Object[] eObjs ) { Collection<EObject> relObjects = new ArrayList<EObject>(); for (Object eObj : eObjs) { if( eObj instanceof Table || eObj instanceof View || eObj instanceof Procedure || eObj instanceof ProcedureResult || eObj instanceof Schema || eObj instanceof Catalog || eObj instanceof Column || eObj instanceof ProcedureParameter || eObj instanceof Interface || eObj instanceof Operation || eObj instanceof XmlDocument) { relObjects.add((EObject)eObj); } } return relObjects.toArray(); } /* * Returns an image for the element. Targeted for Column 1 in the Tree corresponding to the Model and it's children. * */ private Image getImage( Object element ) { if (element instanceof EObject) { return ModelUtilities.getEMFLabelProvider().getImage(element); } else if (element instanceof Resource) { try { EObject firstEObj = ((Resource)element).getContents().get(0); ModelAnnotation ma = ModelerCore.getModelEditor().getModelAnnotation(firstEObj); ModelType mType = ma.getModelType(); if (ModelType.PHYSICAL_LITERAL == mType) { return ModelIdentifier.getImage(ModelIdentifier.RELATIONAL_SOURCE_MODEL_ID); } if( ModelIdentifier.isFunctionModelUri(ma.getPrimaryMetamodelUri())) { return ModelIdentifier.getImage(ModelIdentifier.FUNCTION_MODEL_ID); } if( ModelIdentifier.isXmlViewModel(ma.getPrimaryMetamodelUri())) { return ModelIdentifier.getImage(ModelIdentifier.XML_VIEW_MODEL_ID); } if( ModelIdentifier.isWebServicesViewModel(ma.getPrimaryMetamodelUri())) { return ModelIdentifier.getImage(ModelIdentifier.WEB_SERVICES_VIEW_MODEL_ID); } return ModelIdentifier.getImage(ModelIdentifier.RELATIONAL_VIEW_MODEL_ID); } catch (ModelerCoreException e) { RolesUiPlugin.UTIL.log(IStatus.ERROR, RolesUiPlugin.UTIL.getString("errorFindingImageForObject", element, e)); //$NON-NLS-1$ } } return null; } @Override public Object getParent( Object element ) { if (element instanceof EObject) { return ModelUtilities.getModelContentProvider().getParent(element); } else if (element instanceof Resource) { return ((Resource)element).getResourceSet(); } return null; } private Image getSecurityStatusImage(Object target) { Permission perm = this.handler.getPermission(target); if( perm != null ) { if( allowsRowFilter(target) || allowsColumnMask(target) ) { if( perm.getCondition() != null || perm.getMask() != null ) { return BLUE_STATUS_BOX; } return WHITE_STATUS_BOX; } else { return GRAY_STATUS_BOX; } } else if( allowsRowFilter(target) || allowsColumnMask(target) ){ return WHITE_STATUS_BOX; } return GRAY_STATUS_BOX; } /** * Returns a string target name for the specified element * */ public String getTargetName( Object element ) { String targetName = null; if (element instanceof Resource) { return getResourceName((Resource)element); } else if (element instanceof EObject) { EObject eObj = (EObject)element; targetName = getResourceName(eObj.eResource()) + '/' + ModelerCore.getModelEditor().getModelRelativePath(eObj); } if(targetName!=null) { targetName = targetName.replace(B_SLASH, DELIM); } return targetName; } /** * Returns an actual Model Object (EObject or Resource) for the specified Permission * * * @param perm * @return */ public Object getPermissionTargetObject( Permission perm ) { String targetName = perm.getTargetName(); for (Resource res : resources) { if (getTargetName(res).equals(targetName)) { return res; } for (Object child : getChildren(res)) { if (getTargetName(child).equals(targetName)) { return child; } Object target = getTargetObjectInChildren(child, targetName); if (target != null) { return target; } } } return null; } /* * Returns the file name only minus the xmi file extension */ private String getResourceName( Resource res ) { if (res.getURI().path().endsWith(".xmi")) { //$NON-NLS-1$ Path path = new Path(res.getURI().path()); return path.removeFileExtension().lastSegment(); } return res.getURI().path(); } /* * Finds the target object under the specified parent. May return null. * */ private Object getTargetObjectInChildren(Object parent, String targetName) { for (Object child : getChildren(parent)) { if (getTargetName(child).equals(targetName)) { return child; } Object target = getTargetObjectInChildren(child, targetName); if (target != null) { return target; } } return null; } /* * Helper method to retrieve the text value for an EMF object (EObject or Resource) * */ private String getText( Object element ) { if (element instanceof EObject) { ILabelProvider p = ModelUtilities.getEMFLabelProvider(); return p.getText(element); } else if (element instanceof Resource) { return ((Resource)element).getURI().lastSegment(); } return StringConstants.EMPTY_STRING; } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { // NO OP } @Override public boolean isLabelProperty(Object element, String property) { // NO OP return false; } /* * Make sure that ALL resources have a permissions object?? */ private void reInitializePermissions() { if (handler.hasPermissions()) { return; } for (Resource res : resources) { String resPath = getTargetName(res); Permission perm = new Permission(resPath, false, true, false, false, false, false); perm.setPrimary(true); handler.addPermission(res, perm); } } @Override public void removeListener( ILabelProviderListener listener ) { // NO OPisRowFilter } /** * Performs the necessary permission CRUD value changes based on the target element and the CRUD type. * This method is targeted for use by a single-click editor changing ONE CRUD boolean value for one object. * * @param element * @param crudType */ public void togglePermission( Object element, Crud.Type crudType ) { handler.toggleElementPermission(element, crudType); } /** * Get any warnings which we may need to show the user, before toggling. * * @param element * @param crudType * @return IStatus status toggle warnings to display, if any */ public IStatus getToggleStatus( Object element, Crud.Type crudType ) { return handler.getToggleStatus(element, crudType); } public void loadPermissions(Collection<Permission> permissions) { this.handler.loadPermissions(permissions); } public Collection<Permission> getPermissions() { return this.handler.getPermissions(); } public List<Permission> getPermissionsWithRowBasedSecurity() { return this.handler.getPermissionsWithRowBasedSecurity(); } public Permission getPermission(String targetName) { return this.handler.getPermission(targetName); } public Permission getPermission(Object element) { return this.handler.getPermission(element); } public List<Permission> getPermissionsWithColumnMasking() { return handler.getPermissionsWithColumnMasking(); } public void removeRowBasedSecurity(Permission permission) { this.handler.removeRowBasedSecurity(permission); } public void setRowsBasedSecurity(String targetName, String condition, boolean constraint) { this.handler.setRowsBasedSecurity(targetName, condition, constraint); } public void removeColumnMask(Permission permission) { this.handler.removeColumnMask(permission); } public void removeColumnMask(String targetName) { this.handler.removeColumnMask(targetName); } public void setColumnMask(String targetName, String condition, String mask, int order) { this.handler.setColumnMask(targetName, condition, mask, order); } public List<String> getAllowedLanguages() { return this.handler.getAllowedLanguages(); } public void addAllowedLanguage(String language) { this.handler.addAllowedLanguage(language); } public void removeAllowedLanguage(String language) { this.handler.removeAllowedLanguage(language); } public Permission createPermission(Object target) { String targetName = getTargetName(target); Permission perm = new Permission(targetName, new Crud(null, null, null, null, null, null)); perm.setCanFilter(allowsRowFilter(target)); perm.setCanMask(allowsColumnMask(target)); this.handler.addPermission(target, perm); return perm; } public boolean allowsRowFilter(Object target) { return (target instanceof Table || target instanceof View || target instanceof Procedure); } public boolean allowsColumnMask(Object target) { return target instanceof Column; } public boolean allowsCondition(Object target) { return allowsColumnMask(target) || allowsRowFilter(target); } public String getSecurityDialogMessage(Object target) { if( target instanceof Column ) { return NLS.bind(Messages.setSecurityValuesFor_0_message, Messages.column); } else if( target instanceof Table ) { return NLS.bind(Messages.setSecurityValuesFor_0_message, Messages.table); } else if( target instanceof View ) { return NLS.bind(Messages.setSecurityValuesFor_0_message, Messages.view); } else if( target instanceof Procedure ) { return NLS.bind(Messages.setSecurityValuesFor_0_message, Messages.procedure); } return StringConstants.EMPTY_STRING; } public void handlePermissionChanged(Permission permission) { this.handler.handlePermissionChanged(permission); } }