/** * (C) Copyright 2013 Jabylon (http://www.jabylon.org) and others. * * 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 */ package org.jabylon.common.review.internal; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.Service; import org.eclipse.emf.cdo.transaction.CDOTransaction; import org.eclipse.emf.cdo.util.CommitException; import org.eclipse.emf.common.notify.Notification; import org.jabylon.cdo.connector.TransactionUtil; import org.jabylon.common.review.ReviewParticipant; import org.jabylon.common.util.PreferencesUtil; import org.jabylon.properties.Project; import org.jabylon.properties.Property; import org.jabylon.properties.PropertyFile; import org.jabylon.properties.PropertyFileDescriptor; import org.jabylon.properties.Review; import org.jabylon.resources.changes.PropertiesListener; import org.jabylon.resources.persistence.PropertyPersistenceService; import org.osgi.service.prefs.Preferences; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Johannes Utzig (jutzig.dev@googlemail.com) * */ @Component @Service public class PropertyReviewService implements PropertiesListener { @Reference(referenceInterface=ReviewParticipant.class,bind="addParticipant",unbind="removeParticipant",cardinality=ReferenceCardinality.MANDATORY_MULTIPLE) private List<ReviewParticipant> participants = Collections.synchronizedList(new ArrayList<ReviewParticipant>()); @Reference(referenceInterface=PropertyPersistenceService.class,bind="setPersistenceService",unbind="unsetPersistenceService",cardinality=ReferenceCardinality.MANDATORY_UNARY) private PropertyPersistenceService propertyPersistence; private static final Logger logger = LoggerFactory.getLogger(PropertyReviewService.class); public PropertyReviewService() { } protected void addParticipant(ReviewParticipant pariticpant) { logger.info("Adding new review participant {} (ID: {})",pariticpant.getName(),pariticpant.getID()); participants.add(pariticpant); } protected void removeParticipant(ReviewParticipant pariticpant) { logger.info("Deactivating review participant {} (ID: {})",pariticpant.getName(),pariticpant.getID()); participants.remove(pariticpant); } protected void setPersistenceService(PropertyPersistenceService persistence) { this.propertyPersistence = persistence; } protected void unsetPersistenceService(PropertyPersistenceService persistence) { this.propertyPersistence = null; } @Override public void propertyFileAdded(PropertyFileDescriptor descriptor, boolean autoSync) { if (descriptor.isMaster()) // TODO: or does the master language need to // be checked too return; Project project = descriptor.getProjectLocale().getParent().getParent(); List<ReviewParticipant> activeReviews = getActiveReviews(project); if (activeReviews.isEmpty()) return; PropertyFile slaveProperties = null; PropertyFile masterProperties = null; try { slaveProperties = propertyPersistence.loadProperties(descriptor); masterProperties = propertyPersistence.loadProperties(descriptor.getMaster()); } catch (Exception e1) { logger.error("failed to load properties for "+descriptor.getLocation(),e1); return; } CDOTransaction transaction = TransactionUtil.configureView(descriptor.cdoView().getSession().openTransaction()); descriptor = transaction.getObject(descriptor); Set<String> allProperties = new HashSet<String>(); for (Property prop : slaveProperties.getProperties()) { String key = prop.getKey(); if (key == null) // TODO: how can this happen? continue; allProperties.add(key); Property masterProperty = masterProperties.getProperty(key); for (ReviewParticipant reviewer : activeReviews) { Review review = null; if (descriptor.isMaster()) { review = reviewer.review(descriptor, prop, null); } else { review = reviewer.review(descriptor, masterProperty, prop); } if (review != null) { review.setKey(prop.getKey()); descriptor.getReviews().add(review); } } } if (!descriptor.isMaster()) { // process all properties that are missing in the slave for (Property property : masterProperties.getProperties()) { if (allProperties.contains(property.getKey())) continue; // already processed for (ReviewParticipant reviewer : activeReviews) { Review review = reviewer.review(descriptor, property, null); if (review != null) { review.setKey(property.getKey()); descriptor.getReviews().add(review); } } } } try { if (transaction.isDirty()) { transaction.commit(); } } catch (CommitException e) { logger.error("Commit failed",e); } finally { transaction.close(); } } /** * deletes all review for the given property key * @param key * @param reviews */ private void removeKey(String key, List<Review> reviews) { //TODO: is it wise to delete all reviews? Iterator<Review> it = reviews.iterator(); while (it.hasNext()) { Review review = (Review) it.next(); if (key.equals(review.getKey())) { it.remove(); } } } @Override public void propertyFileDeleted(PropertyFileDescriptor descriptor, boolean autoSync) { // nothing to do } @SuppressWarnings("unchecked") @Override public void propertyFileModified(PropertyFileDescriptor descriptor, List<Notification> changes, boolean autoSync) { Project project = descriptor.getProjectLocale().getParent().getParent(); List<ReviewParticipant> activeReviews = getActiveReviews(project); if (activeReviews.isEmpty()) return; CDOTransaction transaction = TransactionUtil.configureView(descriptor.cdoView().getSession().openTransaction()); descriptor = transaction.getObject(descriptor); PropertyFile masterProperties = null; if (!descriptor.isMaster()) { try { masterProperties = propertyPersistence.loadProperties(descriptor.getMaster()); } catch (Exception e) { logger.error("failed to load properties for "+descriptor.getMaster().getLocation(),e); return; } } for (Notification change : changes) { Object notifier = change.getNotifier(); if (notifier instanceof Property) { Property prop = (Property) notifier; analyzeProperty(descriptor, activeReviews, masterProperties, prop); } else if (notifier instanceof PropertyFile) { Object newValue = change.getNewValue(); if (change.getEventType() == Notification.ADD && newValue instanceof Property) { Property property = (Property) newValue; analyzeProperty(descriptor, activeReviews, masterProperties, property); } else if (change.getEventType() == Notification.ADD_MANY && newValue instanceof Collection) { Collection<Property> properties = (Collection<Property>) newValue; for (Property property : properties) { analyzeProperty(descriptor, activeReviews, masterProperties, property); } } } } try { if (transaction.isDirty()) { transaction.commit(); } } catch (CommitException e) { logger.error("Commit failed",e); } finally { transaction.close(); } } protected void analyzeProperty(PropertyFileDescriptor descriptor, List<ReviewParticipant> activeReviews, PropertyFile masterProperties, Property prop) { removeKey(prop.getKey(), descriptor.getReviews()); Property masterProp = masterProperties.getProperty(prop.getKey()); for (ReviewParticipant reviewer : activeReviews) { Review review = null; if (descriptor.isMaster()) { review = reviewer.review(descriptor, prop, null); } else { review = reviewer.review(descriptor, masterProp, prop); } if (review != null) { review.setKey(prop.getKey()); descriptor.getReviews().add(review); } } } private List<ReviewParticipant> getActiveReviews(Project project) { List<ReviewParticipant> activeParticipants = new ArrayList<ReviewParticipant>(); Preferences node = PreferencesUtil.scopeFor(project).node(PreferencesUtil.NODE_CHECKS); for (ReviewParticipant participant : participants) { if (node.getBoolean(participant.getID(), false)) activeParticipants.add(participant); } return activeParticipants; } public Collection<Review> review(PropertyFileDescriptor descriptor, Property master, Property slave) { List<Review> reviews = new ArrayList<Review>(); List<ReviewParticipant> participants = getActiveReviews(descriptor.getProjectLocale().getParent().getParent()); for (ReviewParticipant reviewParticipant : participants) { Review review = reviewParticipant.review(descriptor, master, slave); if (review != null) reviews.add(review); } return reviews; } }