package com.thinkbiganalytics.metadata.modeshape.sla; /*- * #%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.thinkbiganalytics.metadata.api.MetadataAccess; import com.thinkbiganalytics.metadata.api.PostMetadataConfigAction; import com.thinkbiganalytics.metadata.api.extension.ExtensibleEntity; import com.thinkbiganalytics.metadata.api.extension.ExtensibleEntityProvider; import com.thinkbiganalytics.metadata.api.extension.ExtensibleType; import com.thinkbiganalytics.metadata.api.extension.ExtensibleTypeProvider; import com.thinkbiganalytics.metadata.api.extension.FieldDescriptor; import com.thinkbiganalytics.metadata.api.feed.Feed; import com.thinkbiganalytics.metadata.api.feed.FeedProvider; import com.thinkbiganalytics.metadata.api.sla.FeedServiceLevelAgreement; import com.thinkbiganalytics.metadata.api.sla.FeedServiceLevelAgreementProvider; import com.thinkbiganalytics.metadata.api.sla.FeedServiceLevelAgreementRelationship; import com.thinkbiganalytics.metadata.modeshape.JcrMetadataAccess; import com.thinkbiganalytics.metadata.modeshape.MetadataRepositoryException; import com.thinkbiganalytics.metadata.modeshape.extension.JcrExtensibleEntity; import com.thinkbiganalytics.metadata.modeshape.feed.JcrFeed; import com.thinkbiganalytics.metadata.modeshape.support.JcrQueryUtil; import com.thinkbiganalytics.metadata.sla.api.ServiceLevelAgreement; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import javax.inject.Inject; import javax.jcr.Node; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.query.QueryResult; import javax.jcr.query.Row; import javax.jcr.query.RowIterator; /** */ public class JcrFeedServiceLevelAgreementProvider implements FeedServiceLevelAgreementProvider, PostMetadataConfigAction { @Inject FeedProvider feedProvider; @Inject private ExtensibleTypeProvider typeProvider; @Inject private ExtensibleEntityProvider entityProvider; @Inject private JcrMetadataAccess metadata; private AtomicBoolean typeCreated = new AtomicBoolean(false); /** * Finds All Service Level Agreements and also adds in an related feeds * Filter out the Precondition SLAs as those are not to be managed via the SLA screen. */ @Override public List<FeedServiceLevelAgreement> findAllAgreements() { String query = "SELECT * from [" + JcrServiceLevelAgreement.NODE_TYPE + "] AS sla " + "JOIN [" + JcrFeedServiceLevelAgreementRelationship.NODE_TYPE + "] AS feedSla ON feedSla.[" + JcrFeedServiceLevelAgreementRelationship.SLA + "] = sla.[jcr:uuid] "; return queryToList(query, null); } @Override public void run() { createType(); } private List<FeedServiceLevelAgreement> queryToList(String query, Map<String, String> params) { QueryResult result = null; try { result = JcrQueryUtil.query(getSession(), query, params); List<FeedServiceLevelAgreement> entities = new ArrayList<>(); if (result != null) { try { RowIterator rowIterator = result.getRows(); while (rowIterator.hasNext()) { Row row = rowIterator.nextRow(); Node slaNode = row.getNode("sla"); Set<JcrFeed> feeds = null; Node feedSlaNode = row.getNode("feedSla"); //Left Join will result in the node being NULL if its not there if (feedSlaNode != null) { JcrFeedServiceLevelAgreementRelationship feedServiceLevelAgreementRelationship = new JcrFeedServiceLevelAgreementRelationship(feedSlaNode); feeds = (Set<JcrFeed>) feedServiceLevelAgreementRelationship.getFeeds(); } JcrFeedServiceLevelAgreement entity = new JcrFeedServiceLevelAgreement(slaNode, feeds); entities.add(entity); } } catch (RepositoryException e) { throw new MetadataRepositoryException("Unable to parse QueryResult to List for feedSla", e); } } return entities; } catch (RepositoryException e) { throw new MetadataRepositoryException("Unable to execute Feed SLA Query. Query is: " + query, e); } } public FeedServiceLevelAgreement findAgreement(ServiceLevelAgreement.ID id) { String query = "SELECT * from [" + JcrServiceLevelAgreement.NODE_TYPE + "] AS sla " + "LEFT JOIN [" + JcrFeedServiceLevelAgreementRelationship.NODE_TYPE + "] AS feedSla ON feedSla.[" + JcrFeedServiceLevelAgreementRelationship.SLA + "] = sla.[jcr:uuid] " + "WHERE sla.[jcr:uuid] = $slaId "; Map<String, String> bindParams = new HashMap<>(); bindParams.put("slaId", id.toString()); List<FeedServiceLevelAgreement> list = queryToList(query, bindParams); if (list != null && !list.isEmpty()) { return list.get(0); } return null; } public List<FeedServiceLevelAgreement> findFeedServiceLevelAgreements(Feed.ID feedId) { String query = "SELECT * from [" + JcrServiceLevelAgreement.NODE_TYPE + "] AS sla " + "JOIN [" + JcrFeedServiceLevelAgreementRelationship.NODE_TYPE + "] AS feedSla ON feedSla.[" + JcrFeedServiceLevelAgreementRelationship.SLA + "] = sla.[jcr:uuid] " + "WHERE feedSla.[" + JcrFeedServiceLevelAgreementRelationship.FEEDS + "] IN ('" + feedId.toString() + "')"; List<FeedServiceLevelAgreement> list = queryToList(query, null); return list; } public List<ExtensibleEntity> findAllRelationships() { return entityProvider.getEntities(JcrFeedServiceLevelAgreementRelationship.NODE_TYPE); } public FeedServiceLevelAgreementRelationship findRelationship(ServiceLevelAgreement.ID id) { List<? extends ExtensibleEntity> entities = entityProvider.findEntitiesMatchingProperty(JcrFeedServiceLevelAgreementRelationship.NODE_TYPE, JcrFeedServiceLevelAgreementRelationship.SLA, id); if (entities != null && !entities.isEmpty()) { return new JcrFeedServiceLevelAgreementRelationship((JcrExtensibleEntity) entities.get(0)); } return null; } /** * Returns the relationship object for SLA to a Set of Feeds */ public FeedServiceLevelAgreementRelationship getRelationship(ExtensibleEntity.ID id) { ExtensibleEntity entity = entityProvider.getEntity(id); return new JcrFeedServiceLevelAgreementRelationship((JcrExtensibleEntity) entity); } /** * Creates the Extensible Entity Type */ public String createType() { // TODO service? if (typeCreated.compareAndSet(false, true)) { return metadata.commit(() -> { ExtensibleType feedSla = typeProvider.getType(JcrFeedServiceLevelAgreementRelationship.TYPE_NAME); if (feedSla == null) { feedSla = typeProvider.buildType(JcrFeedServiceLevelAgreementRelationship.TYPE_NAME) // @formatter:off .field(JcrFeedServiceLevelAgreementRelationship.FEEDS) .type(FieldDescriptor.Type.WEAK_REFERENCE) .displayName("Feeds") .description("The Feeds referenced on this SLA") .required(false) .collection(true) .add() .field(JcrFeedServiceLevelAgreementRelationship.SLA) .type(FieldDescriptor.Type.WEAK_REFERENCE) .displayName("SLA") .description("The SLA") .required(true) .add() .build(); // @formatter:on } return feedSla.getName(); }, MetadataAccess.SERVICE); } return null; } /** * Create/Update the Relationship between a SLA and a Set of Feeds */ @Override public FeedServiceLevelAgreementRelationship relate(ServiceLevelAgreement sla, Set<Feed.ID> feedIds) { JcrFeedServiceLevelAgreementRelationship relationship = null; //find if this relationship already exists Set<Node> feedNodes = new HashSet<>(); Map<String, Object> props = new HashMap<>(); Set<Feed> feeds = new HashSet<>(); for (Feed.ID feedId : feedIds) { Feed feed = feedProvider.getFeed(feedId); if (feed != null) { feeds.add(feed); } } return relateFeeds(sla, feeds); } @Override public FeedServiceLevelAgreementRelationship relateFeeds(ServiceLevelAgreement sla, Set<Feed> feeds) { JcrFeedServiceLevelAgreementRelationship relationship = null; //find if this relationship already exists JcrFeedServiceLevelAgreementRelationship feedSla = (JcrFeedServiceLevelAgreementRelationship) findRelationship(sla.getId()); Set<Node> feedNodes = new HashSet<>(); Map<String, Object> props = new HashMap<>(); for (Feed feed : feeds) { if (feed != null) { JcrFeed jcrFeed = (JcrFeed) feed; feedNodes.add(jcrFeed.getNode()); } } props.put(JcrFeedServiceLevelAgreementRelationship.FEEDS, feedNodes); props.put(JcrFeedServiceLevelAgreementRelationship.SLA, ((JcrServiceLevelAgreement) sla).getNode()); //remove any existing relationships removeFeedRelationships(sla.getId()); if (feedSla == null) { ExtensibleType type = typeProvider.getType(JcrFeedServiceLevelAgreementRelationship.TYPE_NAME); JcrExtensibleEntity entity = (JcrExtensibleEntity) entityProvider.createEntity(type, props); relationship = new JcrFeedServiceLevelAgreementRelationship(entity.getNode()); } else { JcrExtensibleEntity entity = (JcrExtensibleEntity) entityProvider.updateEntity(feedSla, props); relationship = new JcrFeedServiceLevelAgreementRelationship(entity.getNode()); } //update the feed relationships for (Feed feed : feeds) { feedProvider.updateFeedServiceLevelAgreement(feed.getId(), sla); } return relationship; } @Override public boolean removeFeedRelationships(ServiceLevelAgreement.ID id) { try { Session session = getSession(); JcrFeedServiceLevelAgreementRelationship extensibleEntity = (JcrFeedServiceLevelAgreementRelationship) findRelationship(id); if (extensibleEntity != null) { JcrMetadataAccess.ensureCheckoutNode(extensibleEntity.getNode()); for (final Feed feed : extensibleEntity.getFeeds()) { if (feed != null) { final JcrFeed jcrFeed = (JcrFeed) feed; JcrMetadataAccess.ensureCheckoutNode(jcrFeed.getNode()); } } return extensibleEntity.removeFeedRelationships(id); } } catch (RepositoryException e) { throw new MetadataRepositoryException("unable to remove Feed SLA relationships for SLA " + id, e); } return false; } public boolean removeAllRelationships(ServiceLevelAgreement.ID id) { try { Session session = getSession(); JcrFeedServiceLevelAgreementRelationship extensibleEntity = (JcrFeedServiceLevelAgreementRelationship) findRelationship(id); if (extensibleEntity != null) { JcrMetadataAccess.ensureCheckoutNode(extensibleEntity.getNode()); for (final Feed feed : extensibleEntity.getFeeds()) { if (feed != null) { final JcrFeed jcrFeed = (JcrFeed) feed; JcrMetadataAccess.ensureCheckoutNode(jcrFeed.getNode()); } } extensibleEntity.removeFeedRelationships(id); extensibleEntity.getNode().remove(); } } catch (RepositoryException e) { throw new MetadataRepositoryException("unable to remove Feed SLA relationships for SLA " + id, e); } return false; } protected Session getSession() { return JcrMetadataAccess.getActiveSession(); } }