/**
*
*/
package com.thinkbiganalytics.metadata.modeshape.feed;
/*-
* #%L
* kylo-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 java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import com.thinkbiganalytics.metadata.api.category.Category;
import com.thinkbiganalytics.metadata.api.datasource.Datasource;
import com.thinkbiganalytics.metadata.api.feed.Feed;
import com.thinkbiganalytics.metadata.api.feed.FeedDestination;
import com.thinkbiganalytics.metadata.api.feed.FeedPrecondition;
import com.thinkbiganalytics.metadata.api.feed.FeedSource;
import com.thinkbiganalytics.metadata.api.template.FeedManagerTemplate;
import com.thinkbiganalytics.metadata.modeshape.MetadataRepositoryException;
import com.thinkbiganalytics.metadata.modeshape.common.JcrPropertiesEntity;
import com.thinkbiganalytics.metadata.modeshape.datasource.JcrDatasource;
import com.thinkbiganalytics.metadata.modeshape.sla.JcrServiceLevelAgreement;
import com.thinkbiganalytics.metadata.modeshape.support.JcrPropertyUtil;
import com.thinkbiganalytics.metadata.modeshape.support.JcrUtil;
import com.thinkbiganalytics.metadata.modeshape.support.JcrVersionUtil;
import com.thinkbiganalytics.metadata.modeshape.template.JcrFeedTemplate;
import com.thinkbiganalytics.metadata.sla.api.ServiceLevelAgreement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
*/
public class FeedDetails extends JcrPropertiesEntity {
private static final Logger log = LoggerFactory.getLogger(FeedDetails.class);
public static final String NODE_TYPE = "tba:feedDetails";
public static final String FEED_JSON = "tba:json";
public static final String PROCESS_GROUP_ID = "tba:processGroupId";
public static final String FEED_TEMPLATE = "tba:feedTemplate";
public static final String PRECONDITION = "tba:precondition";
public static final String DEPENDENTS = "tba:dependentFeeds";
public static final String USED_BY_FEEDS = "tba:usedByFeeds";
public static final String SOURCE_NAME = "tba:sources";
public static final String DESTINATION_NAME = "tba:destinations";
public static final String TEMPLATE = "tba:feedTemplate";
public static final String SLA = "tba:slas";
private FeedSummary summary;
/**
* @param node
*/
public FeedDetails(Node node, FeedSummary summary) {
super(node);
this.summary = summary;
}
protected JcrFeed getParentFeed() {
return this.summary.getParentFeed();
}
protected FeedSummary getParentSummary() {
return this.summary;
}
public List<? extends FeedSource> getSources() {
return JcrUtil.getJcrObjects(this.node, SOURCE_NAME, JcrFeedSource.class);
}
public List<? extends FeedDestination> getDestinations() {
return JcrUtil.getJcrObjects(this.node, DESTINATION_NAME, JcrFeedDestination.class);
}
public <C extends Category> List<Feed> getDependentFeeds() {
List<Feed> deps = new ArrayList<>();
Set<Node> depNodes = JcrPropertyUtil.getSetProperty(this.node, DEPENDENTS);
for (Node depNode : depNodes) {
deps.add(new JcrFeed(depNode, this.summary.getParentFeed().getOpsAccessProvider().orElse(null)));
}
return deps;
}
public boolean addDependentFeed(Feed feed) {
JcrFeed dependent = (JcrFeed) feed;
Node depNode = dependent.getNode();
feed.addUsedByFeed(getParentFeed());
return JcrPropertyUtil.addToSetProperty(this.node, DEPENDENTS, depNode, true);
}
public boolean removeDependentFeed(Feed feed) {
JcrFeed dependent = (JcrFeed) feed;
Node depNode = dependent.getNode();
feed.removeUsedByFeed(getParentFeed());
boolean weakRef = false;
Optional<Property> prop = JcrPropertyUtil.findProperty(this.node, DEPENDENTS);
if (prop.isPresent()) {
try {
weakRef = PropertyType.WEAKREFERENCE == prop.get().getType();
} catch (RepositoryException e) {
log.error("Error removeDependentFeed for {}. Unable to identify if the property is a Weak Reference or not {} ", feed.getName(), e.getMessage(), e);
}
}
return JcrPropertyUtil.removeFromSetProperty(this.node, DEPENDENTS, depNode, weakRef);
}
public boolean addUsedByFeed(Feed feed) {
JcrFeed dependent = (JcrFeed) feed;
Node depNode = dependent.getNode();
return JcrPropertyUtil.addToSetProperty(this.node, USED_BY_FEEDS, depNode, true);
}
public List<Feed> getUsedByFeeds() {
List<Feed> deps = new ArrayList<>();
Set<Node> depNodes = JcrPropertyUtil.getSetProperty(this.node, USED_BY_FEEDS);
for (Node depNode : depNodes) {
deps.add(new JcrFeed(depNode, this.summary.getParentFeed().getOpsAccessProvider().orElse(null)));
}
return deps;
}
public boolean removeUsedByFeed(Feed feed) {
JcrFeed dependent = (JcrFeed) feed;
Node depNode = dependent.getNode();
boolean weakRef = false;
Optional<Property> prop = JcrPropertyUtil.findProperty(this.node, USED_BY_FEEDS);
if (prop.isPresent()) {
try {
weakRef = PropertyType.WEAKREFERENCE == prop.get().getType();
} catch (RepositoryException e) {
log.error("Error removeUsedByFeed for {}. Unable to identify if the property is a Weak Reference or not {} ", feed.getName(), e.getMessage(), e);
}
}
return JcrPropertyUtil.removeFromSetProperty(this.node, USED_BY_FEEDS, depNode, weakRef);
}
public FeedSource getSource(final Datasource.ID id) {
List<? extends FeedSource> sources = getSources();
if (sources != null) {
return sources.stream().filter(feedSource -> feedSource.getDatasource().getId().equals(id)).findFirst().orElse(null);
}
return null;
}
public FeedDestination getDestination(final Datasource.ID id) {
List<? extends FeedDestination> destinations = getDestinations();
if (destinations != null) {
return destinations.stream().filter(feedDestination -> feedDestination.getDatasource().getId().equals(id)).findFirst().orElse(null);
}
return null;
}
public FeedPrecondition getPrecondition() {
try {
if (this.node.hasNode(PRECONDITION)) {
return new JcrFeedPrecondition(this.node.getNode(PRECONDITION), getParentFeed());
} else {
return null;
}
} catch (RepositoryException e) {
throw new MetadataRepositoryException("Failed to retrieve the feed precondition", e);
}
}
public FeedManagerTemplate getTemplate() {
return getProperty(TEMPLATE, JcrFeedTemplate.class);
}
public void setTemplate(FeedManagerTemplate template) {
setProperty(TEMPLATE, template);
template.addFeed(getParentFeed());
}
public List<ServiceLevelAgreement> getServiceLevelAgreements() {
Set<Node> list = JcrPropertyUtil.getReferencedNodeSet(this.node, SLA);
List<ServiceLevelAgreement> serviceLevelAgreements = new ArrayList<>();
if (list != null) {
for (Node n : list) {
serviceLevelAgreements.add(JcrUtil.createJcrObject(n, JcrServiceLevelAgreement.class));
}
}
return serviceLevelAgreements;
}
public void setServiceLevelAgreements(List<? extends ServiceLevelAgreement> serviceLevelAgreements) {
setProperty(SLA, serviceLevelAgreements);
}
public void removeServiceLevelAgreement(ServiceLevelAgreement.ID id) {
try {
Set<Node> nodes = JcrPropertyUtil.getSetProperty(this.node, SLA);
Set<Value> updatedSet = new HashSet<>();
for (Node node : nodes) {
if (!node.getIdentifier().equalsIgnoreCase(id.toString())) {
Value value = this.node.getSession().getValueFactory().createValue(node, true);
updatedSet.add(value);
}
}
node.setProperty(SLA, (Value[]) updatedSet.stream().toArray(size -> new Value[size]));
} catch (RepositoryException e) {
throw new MetadataRepositoryException("Unable to remove reference to SLA " + id + "from feed " + this.getId());
}
}
public boolean addServiceLevelAgreement(ServiceLevelAgreement sla) {
JcrServiceLevelAgreement jcrServiceLevelAgreement = (JcrServiceLevelAgreement) sla;
Node node = jcrServiceLevelAgreement.getNode();
//add a ref to this node
return JcrPropertyUtil.addToSetProperty(this.node, SLA, node, true);
}
public String getJson() {
return getProperty(FeedDetails.FEED_JSON, String.class);
}
public void setJson(String json) {
setProperty(FeedDetails.FEED_JSON, json);
}
public String getNifiProcessGroupId() {
return getProperty(FeedDetails.PROCESS_GROUP_ID, String.class);
}
public void setNifiProcessGroupId(String id) {
setProperty(FeedDetails.PROCESS_GROUP_ID, id);
}
protected JcrFeedSource ensureFeedSource(JcrDatasource datasource) {
Node feedSrcNode = JcrUtil.addNode(getNode(), FeedDetails.SOURCE_NAME, JcrFeedSource.NODE_TYPE);
return new JcrFeedSource(feedSrcNode, datasource);
}
protected JcrFeedDestination ensureFeedDestination(JcrDatasource datasource) {
Node feedDestNode = JcrUtil.addNode(getNode(), FeedDetails.DESTINATION_NAME, JcrFeedDestination.NODE_TYPE);
return new JcrFeedDestination(feedDestNode, datasource);
}
protected void removeFeedSource(JcrFeedSource source) {
try {
JcrVersionUtil.checkout(source.getNode().getParent());
source.getNode().remove();
} catch (RepositoryException e) {
throw new MetadataRepositoryException("nable to remove feed source for feed " + getParentSummary().getSystemName(), e);
}
}
protected void removeFeedDestination(JcrFeedDestination dest) {
try {
JcrVersionUtil.checkout(dest.getNode().getParent());
dest.getNode().remove();
} catch (RepositoryException e) {
throw new MetadataRepositoryException("nable to remove feed destination for feed " + getParentSummary().getSystemName(), e);
}
}
protected void removeFeedSources() {
try {
List<? extends FeedSource> sources = getSources();
if (sources != null && !sources.isEmpty()) {
//checkout the feed
JcrVersionUtil.checkout(getParentSummary().getNode());
sources.stream().forEach(source -> {
try {
Node sourceNode = ((JcrFeedSource) source).getNode();
((JcrDatasource) ((JcrFeedSource) source).getDatasource()).removeSourceNode(sourceNode);
sourceNode.remove();
} catch (RepositoryException e) {
e.printStackTrace();
}
});
}
} catch (RepositoryException e) {
throw new MetadataRepositoryException("nable to remove feed sources for feed " + getParentSummary().getSystemName(), e);
}
}
protected void removeFeedDestinations() {
try {
List<? extends FeedDestination> destinations = getDestinations();
if (destinations != null && !destinations.isEmpty()) {
JcrVersionUtil.checkout(getParentSummary().getNode());
destinations.stream().forEach(dest -> {
try {
Node destNode = ((JcrFeedDestination) dest).getNode();
((JcrDatasource) ((JcrFeedDestination) dest).getDatasource()).removeDestinationNode(destNode);
destNode.remove();
((JcrFeedDestination) dest).getNode().remove();
} catch (RepositoryException e) {
e.printStackTrace();
}
});
}
} catch (RepositoryException e) {
throw new MetadataRepositoryException("unable to remove feed destinations for feed " + getParentSummary().getSystemName(), e);
}
}
protected Node createNewPrecondition() {
try {
Node feedNode = getNode();
Node precondNode = JcrUtil.getOrCreateNode(feedNode, FeedDetails.PRECONDITION, JcrFeed.PRECONDITION_TYPE, true);
if (precondNode.hasProperty(JcrFeedPrecondition.SLA_REF)) {
precondNode.getProperty(JcrFeedPrecondition.SLA_REF).remove();
}
if (precondNode.hasNode(JcrFeedPrecondition.SLA)) {
precondNode.getNode(JcrFeedPrecondition.SLA).remove();
}
return precondNode.addNode(JcrFeedPrecondition.SLA, JcrFeedPrecondition.SLA_TYPE);
} catch (RepositoryException e) {
throw new MetadataRepositoryException("Failed to create the precondition for feed " + getParentFeed().getId(), e);
}
}
}