package com.thinkbiganalytics.metadata.modeshape.category; /*- * #%L * thinkbig-metadata-modeshape * %% * Copyright (C) 2017 ThinkBig Analytics * %% * 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. * #L% */ import com.google.common.collect.ImmutableMap; import com.thinkbiganalytics.metadata.api.MetadataAccess; import com.thinkbiganalytics.metadata.api.category.Category; import com.thinkbiganalytics.metadata.api.category.CategoryProvider; import com.thinkbiganalytics.metadata.api.category.security.CategoryAccessControl; import com.thinkbiganalytics.metadata.api.extension.ExtensibleType; import com.thinkbiganalytics.metadata.api.extension.ExtensibleTypeProvider; import com.thinkbiganalytics.metadata.api.extension.UserFieldDescriptor; import com.thinkbiganalytics.metadata.modeshape.BaseJcrProvider; import com.thinkbiganalytics.metadata.modeshape.JcrMetadataAccess; import com.thinkbiganalytics.metadata.modeshape.common.EntityUtil; import com.thinkbiganalytics.metadata.modeshape.common.JcrEntity; import com.thinkbiganalytics.metadata.modeshape.extension.ExtensionsConstants; import com.thinkbiganalytics.metadata.modeshape.security.action.JcrAllowedActions; import com.thinkbiganalytics.metadata.modeshape.security.action.JcrAllowedEntityActionsProvider; import com.thinkbiganalytics.metadata.modeshape.support.JcrPropertyUtil; import com.thinkbiganalytics.metadata.modeshape.support.JcrQueryUtil; import com.thinkbiganalytics.metadata.modeshape.support.JcrUtil; import com.thinkbiganalytics.security.AccessController; import com.thinkbiganalytics.security.action.AllowedActions; import com.thinkbiganalytics.security.role.SecurityRole; import com.thinkbiganalytics.security.role.SecurityRoleProvider; import java.io.Serializable; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import javax.annotation.Nonnull; import javax.inject.Inject; import javax.jcr.Node; import javax.jcr.RepositoryException; /** * A JCR provider for {@link Category} objects. */ public class JcrCategoryProvider extends BaseJcrProvider<Category, Category.ID> implements CategoryProvider { /** * JCR node type manager */ @Inject ExtensibleTypeProvider extensibleTypeProvider; @Inject private SecurityRoleProvider roleProvider; @Inject private JcrAllowedEntityActionsProvider actionsProvider; @Inject private AccessController accessController; /** * Transaction support */ @Inject MetadataAccess metadataAccess; @Override public Category update(Category category) { category.getAllowedActions().checkPermission(CategoryAccessControl.EDIT_DETAILS); return super.update(category); } @Override public Category findBySystemName(String systemName) { final String query = "SELECT * FROM [" + getNodeType(getJcrEntityClass()) + "] as cat WHERE cat.[" + JcrCategory.SYSTEM_NAME + "] = $systemName"; return JcrQueryUtil.findFirst(getSession(), query, ImmutableMap.of("systemName", systemName), getEntityClass()); } @Override public String getNodeType(Class<? extends JcrEntity> jcrEntityType) { return JcrCategory.NODE_TYPE; } @Override public Class<? extends Category> getEntityClass() { return JcrCategory.class; } @Override public Class<? extends JcrEntity> getJcrEntityClass() { return JcrCategory.class; } @Override public Category ensureCategory(String systemName) { String path = EntityUtil.pathForCategory(); Map<String, Object> props = new HashMap<>(); props.put(JcrCategory.SYSTEM_NAME, systemName); boolean isNew = ! hasEntityNode(path, systemName); JcrCategory category = (JcrCategory) findOrCreateEntity(path, systemName, props); if (isNew) { if (this.accessController.isEntityAccessControlled()) { List<SecurityRole> roles = this.roleProvider.getEntityRoles(SecurityRole.CATEGORY); this.actionsProvider.getAvailableActions(AllowedActions.CATEGORY) .ifPresent(actions -> category.enableAccessControl((JcrAllowedActions) actions, JcrMetadataAccess.getActiveUser(), roles)); } else { this.actionsProvider.getAvailableActions(AllowedActions.CATEGORY) .ifPresent(actions -> category.disableAccessControl((JcrAllowedActions) actions, JcrMetadataAccess.getActiveUser())); } } return category; } @Override public Category.ID resolveId(Serializable fid) { return new JcrCategory.CategoryId(fid); } @Override public void delete(final Category category) { throw new UnsupportedOperationException(); } @Override public void deleteById(final Category.ID id) { // TODO service? metadataAccess.commit(() -> { // Get category final Category category = findById(id); if (category != null) { // Delete user type final ExtensibleType type = extensibleTypeProvider.getType(ExtensionsConstants.getUserCategoryFeed(category.getName())); if (type != null) { extensibleTypeProvider.deleteType(type.getId()); } // Delete category super.delete(category); } return true; }, MetadataAccess.SERVICE); } @Nonnull @Override public Set<UserFieldDescriptor> getUserFields() { return JcrPropertyUtil.getUserFields(ExtensionsConstants.USER_CATEGORY, extensibleTypeProvider); } @Override public void setUserFields(@Nonnull final Set<UserFieldDescriptor> userFields) { metadataAccess.commit(() -> { JcrPropertyUtil.setUserFields(ExtensionsConstants.USER_CATEGORY, userFields, extensibleTypeProvider); return userFields; }, MetadataAccess.SERVICE); } @Nonnull @Override public Optional<Set<UserFieldDescriptor>> getFeedUserFields(@Nonnull final Category.ID categoryId) { return Optional.ofNullable(findById(categoryId)) .map(category -> JcrPropertyUtil.getUserFields(ExtensionsConstants.getUserCategoryFeed(category.getName()), extensibleTypeProvider)); } @Override public void setFeedUserFields(@Nonnull final Category.ID categoryId, @Nonnull final Set<UserFieldDescriptor> userFields) { metadataAccess.commit(() -> { final Category category = findById(categoryId); JcrPropertyUtil.setUserFields(ExtensionsConstants.getUserCategoryFeed(category.getName()), userFields, extensibleTypeProvider); return userFields; }, MetadataAccess.SERVICE); } @Override public void rename(@Nonnull final Category.ID categoryId, @Nonnull final String newName) { // Move the node to the new path final JcrCategory category = (JcrCategory) findById(categoryId); final Node node = category.getNode(); try { final String newPath = JcrUtil.path(node.getParent().getPath(), newName).toString(); JcrMetadataAccess.getActiveSession().move(node.getPath(), newPath); } catch (final RepositoryException e) { throw new IllegalStateException("Unable to rename category: " + node, e); } // Update properties category.setProperty(JcrCategory.SYSTEM_NAME, newName); // Move user fields final Optional<Set<UserFieldDescriptor>> feedUserFields = getFeedUserFields(category.getId()); if (feedUserFields.isPresent()) { final ExtensibleType type = extensibleTypeProvider.getType(ExtensionsConstants.getUserCategoryFeed(category.getName())); if (type != null) { extensibleTypeProvider.deleteType(type.getId()); } setFeedUserFields(category.getId(), feedUserFields.get()); } } }