Java tutorial
/******************************************************************************* * Copyright (c) 2013 Instituto Superior Tcnico - Joo Antunes * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html * * Contributors: * Luis Silva - ACGHSync * Joo Antunes - initial API and implementation ******************************************************************************/ package pt.ist.maidSyncher.domain.activeCollab; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.eclipse.egit.github.core.Label; import org.eclipse.egit.github.core.service.LabelService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import pt.ist.maidSyncher.api.activeCollab.ACCategory; import pt.ist.maidSyncher.domain.MaidRoot; import pt.ist.maidSyncher.domain.SynchableObject; import pt.ist.maidSyncher.domain.activeCollab.exceptions.TaskNotVisibleException; import pt.ist.maidSyncher.domain.dsi.DSIObject; import pt.ist.maidSyncher.domain.dsi.DSIProject; import pt.ist.maidSyncher.domain.dsi.DSIRepository; import pt.ist.maidSyncher.domain.exceptions.SyncActionError; import pt.ist.maidSyncher.domain.github.GHLabel; import pt.ist.maidSyncher.domain.github.GHRepository; import pt.ist.maidSyncher.domain.sync.EmptySyncActionWrapper; import pt.ist.maidSyncher.domain.sync.SyncActionWrapper; import pt.ist.maidSyncher.domain.sync.SyncEvent; import pt.ist.maidSyncher.utils.MiscUtils; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.google.common.collect.Iterables; public class ACProject extends ACProject_Base { private static final Logger LOGGER = LoggerFactory.getLogger(ACProject.class); //PropertyDescriptor s protected static final String DSC_STATUS = "status"; protected static final String DSC_OVERVIEW = "overview"; protected static final String DSC_NAME = "name"; protected static final String DSC_TYPE = "type"; protected static final String DSC_ARCHIVED = "archived"; protected static final String DSC_BUDGET = "budget"; public ACProject() { super(); setAcInstance(MaidRoot.getInstance().getAcInstance()); } public static ACProject process(pt.ist.maidSyncher.api.activeCollab.ACProject acProject) { return process(acProject, false); } public static ACProject process(pt.ist.maidSyncher.api.activeCollab.ACProject acProject, boolean skipSync) { checkNotNull(acProject); ACProject projectToReturn = (ACProject) findOrCreateAndProccess(acProject, ACProject.class, MaidRoot.getInstance().getAcObjectsSet(), skipSync); return projectToReturn; } public static ACProject findById(long id) { return (ACProject) MiscUtils.findACObjectsById(id, ACProject.class); } public static ACProject findByName(final String name) { checkArgument(StringUtils.isBlank(name) == false, "Name mustn't be blank"); MaidRoot maidRoot = MaidRoot.getInstance(); Optional<ACObject> optional = Iterables.tryFind(maidRoot.getAcObjectsSet(), new Predicate<ACObject>() { @Override public boolean apply(ACObject input) { if (input instanceof ACProject) { ACProject acProject = (ACProject) input; return name.equalsIgnoreCase(acProject.getName()); } else return false; } }); return (ACProject) (optional.isPresent() ? optional.get() : null); } public static Set<ACProject> getActiveProjects() { Set<ACObject> acObjects = MaidRoot.getInstance().getAcObjectsSet(); return new HashSet(Collections2.filter(acObjects, new Predicate<ACObject>() { @Override public boolean apply(ACObject input) { if (input == null) return false; if (ACProject.class.isAssignableFrom(input.getClass())) { ACProject acProject = (ACProject) input; return acProject.getArchived() == false; } return false; } })); } @Override public DSIObject getDSIObject() { return getDsiObjectProject(); } @Override public DSIObject findOrCreateDSIObject() { DSIObject dsiObject = getDSIObject(); if (dsiObject == null) { dsiObject = new DSIProject(); setDsiObjectProject((DSIProject) dsiObject); } return dsiObject; } @Override public SyncActionWrapper sync(SyncEvent syncEvent) { SyncActionWrapper syncActionWrapperToReturn = null; if (syncEvent.getTypeOfChangeEvent().equals(SyncEvent.TypeOfChangeEvent.CREATE)) { //let's try to find the already existing GHLabels that can fit as GHLabels //associated with this DSIProject MaidRoot maidRoot = MaidRoot.getInstance(); syncActionWrapperToReturn = syncCreateEvent(syncEvent); } else if (syncEvent.getTypeOfChangeEvent().equals(SyncEvent.TypeOfChangeEvent.UPDATE)) { syncActionWrapperToReturn = syncUpdateEvent(syncEvent); } else { LOGGER.warn("Read and Delete events not supported yet. " + syncEvent); syncActionWrapperToReturn = new EmptySyncActionWrapper(syncEvent); } return syncActionWrapperToReturn; } private SyncActionWrapper syncUpdateEvent(final SyncEvent syncEvent) { final Set<String> tickedDescriptors = new HashSet<>(); boolean isNowArchivedAux = false; boolean nameChangedAux = false; for (String changedDescriptor : syncEvent.getChangedPropertyDescriptorNames().getUnmodifiableList()) { tickedDescriptors.add(changedDescriptor); switch (changedDescriptor) { case DSC_PERMALINK: case DSC_UPDATED_BY_ID: case DSC_UPDATED_ON: case DSC_BUDGET: case DSC_ID: case DSC_CREATED_ON: case DSC_OVERVIEW: case DSC_URL: case DSC_CREATED_BY_ID: break; //the ones above, there'se no sense in changing anything case DSC_TYPE: case DSC_ARCHIVED: //if archived, got to remove GHLabels isNowArchivedAux = getArchived(); break; case DSC_NAME: //got to change GHLabels nameChangedAux = true; break; case DSC_STATUS: //let's do nothing here break; default: tickedDescriptors.remove(changedDescriptor); //if we did not fall on any of the above //cases, let's remove it from the ticked descriptors } } final boolean isNowArchived = isNowArchivedAux; final boolean nameChanged = nameChangedAux; return new SyncActionWrapper<SynchableObject>() { @Override public Set<SynchableObject> sync() throws SyncActionError { Set<SynchableObject> changedObjects = new HashSet<>(); DSIProject dsiProject = (DSIProject) getDSIObject(); MaidRoot maidRoot = MaidRoot.getInstance(); LabelService labelService = new LabelService(maidRoot.getGitHubClient()); try { if (isNowArchived) { //let us get all the labels, and delete them for (GHLabel ghLabel : dsiProject.getGitHubLabelsSet()) { labelService.deleteLabel(ghLabel.getRepository(), ghLabel.getName()); //remove them ghLabel.delete(); //TODO issue #26 - solve the changedObjects with the deleted question } dsiProject.getGitHubLabelsSet().clear(); return Collections.emptySet(); } else if (nameChanged) { //let us try to reuse all of the reusable labels, //[i.e. the ones already with the correct name] Set<GHLabel> allExistingCorrectLabels = GHLabel .getAllLabelsWith(GHLabel.PROJECT_PREFIX + getName()); Set<GHRepository> allRepositoriesWithAlreadyCorrectLabels = (Set<GHRepository>) Collections2 .transform(allExistingCorrectLabels, new Function<GHLabel, GHRepository>() { @Override public GHRepository apply(GHLabel ghLabel) { if (ghLabel == null) return null; return ghLabel.getRepository(); } }); //getting all labels to be edited - from all repositories Set<GHLabel> labelsToBeEdited = new HashSet<>(dsiProject.getGitHubLabelsSet()); for (GHLabel labelToBeEdited : labelsToBeEdited) { Label labelToEdit = labelService.getLabel(labelToBeEdited.getRepository(), labelToBeEdited.getName()); if (allRepositoriesWithAlreadyCorrectLabels.contains(labelToBeEdited.getRepository())) { //now we have a GHLabel that corresponds to the ACProject that still //has the old name. We should be deprecating it and using the already existing label with the correct name //let us append to this label name, a -DEPRECATED_LABEL labelToEdit.setName(labelToEdit.getName() + "-DEPRECATED_LABEL"); labelToEdit = labelService.editLabel(labelToBeEdited.getRepository(), labelToEdit); } else { //we need to edit it labelToEdit.setName(GHLabel.PROJECT_PREFIX + getName()); labelToEdit = labelService.editLabel(labelToBeEdited.getRepository(), labelToEdit); } //let's apply the changes to the GHLabel try { labelToBeEdited.copyPropertiesFrom(labelToEdit); changedObjects.add(labelToBeEdited); } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException | TaskNotVisibleException e) { throw new Error("oopsie daisy, do it manually", e); } } //now let us associate the GHLabel with this DSIProject dsiProject.getGitHubLabelsSet().clear(); dsiProject.getGitHubLabelsSet().addAll(labelsToBeEdited); } } catch (IOException exception) { throw new SyncActionError(exception, changedObjects); } return changedObjects; } @Override public SyncEvent getOriginatingSyncEvent() { return syncEvent; } @Override public Collection<DSIObject> getSyncDependedDSIObjects() { return Collections.emptySet(); } @Override public Set<java.lang.Class> getSyncDependedTypesOfDSIObjects() { //say that we depend on all of the repositories being synched return Collections.singleton((Class) DSIRepository.class); } @Override public Collection<String> getPropertyDescriptorNamesTicked() { return tickedDescriptors; }; }; } private SyncActionWrapper syncCreateEvent(final SyncEvent syncEvent) { final Set<String> tickedDescriptors = new HashSet<>(); for (String changedDescriptor : syncEvent.getChangedPropertyDescriptorNames().getUnmodifiableList()) { tickedDescriptors.add(changedDescriptor); switch (changedDescriptor) { case DSC_PERMALINK: case DSC_UPDATED_BY_ID: case DSC_UPDATED_ON: case DSC_BUDGET: case DSC_ID: case DSC_CREATED_ON: case DSC_OVERVIEW: case DSC_URL: case DSC_CREATED_BY_ID: break; //the ones above, there'se no sense in changing anything case DSC_TYPE: case DSC_ARCHIVED: case DSC_NAME: case DSC_STATUS: break; default: tickedDescriptors.remove(changedDescriptor); //if we did not fall on any of the above //cases, let's remove it from the ticked descriptors } } return new SyncActionWrapper<SynchableObject>() { @Override public Set<SynchableObject> sync() throws SyncActionError { Set<SynchableObject> changedObjects = new HashSet<>(); try { if (getArchived()) return Collections.emptySet(); Set<GHLabel> labelsToAssignToDSIProject = new HashSet<GHLabel>(); //let us get all of the repositories we need to create a label for Set<GHRepository> repositoriesWeNeedToCreateLabelsFor = new HashSet( MaidRoot.getInstance().getGhRepositoriesSet()); final Set<GHLabel> appliableAndAlreadyExistingLabels = GHLabel .getAllLabelsWith(GHLabel.PROJECT_PREFIX + getName()); for (GHLabel ghLabel : appliableAndAlreadyExistingLabels) { repositoriesWeNeedToCreateLabelsFor.remove(ghLabel.getRepository()); labelsToAssignToDSIProject.add(ghLabel); } //let us create the labels we need to LabelService labelService = new LabelService(MaidRoot.getGitHubClient()); for (GHRepository ghRepository : repositoriesWeNeedToCreateLabelsFor) { Label newLabel = new Label(); newLabel.setName(GHLabel.PROJECT_PREFIX + getName()); Label newlyCreatedLabel = labelService.createLabel(ghRepository, newLabel); labelsToAssignToDSIProject .add(GHLabel.process(newlyCreatedLabel, ghRepository.getId(), true)); } //let us remove the old labels and set the new ones on //the appropriate DSIProject relation DSIProject dsiProject = (DSIProject) getDSIObject(); dsiProject.getGitHubLabelsSet().clear(); dsiProject.getGitHubLabelsSet().addAll(labelsToAssignToDSIProject); changedObjects.addAll(labelsToAssignToDSIProject); //now let's take care of the TaskCategory, i.e., we created a new ACProject //thus we need to create a taskcategory for each repository Set<ACTaskCategory> taskCategoriesDefined = getTaskCategoriesDefinedSet(); Set<String> taskCategoriesNames = new HashSet<>( Collections2.transform(taskCategoriesDefined, new Function<ACTaskCategory, String>() { @Override public String apply(ACTaskCategory acTaskCategory) { if (acTaskCategory == null) return null; return StringUtils.lowerCase(acTaskCategory.getName()); } })); Set<ACCategory> taskCategoriesToCreate = new HashSet<>(); Set<GHRepository> repositoriesToCreateTaskCategoriesFor = new HashSet( MaidRoot.getInstance().getGhRepositoriesSet()); Iterator<GHRepository> repoIterator = repositoriesToCreateTaskCategoriesFor.iterator(); //let's see if any of them are appropriate to be used while (repoIterator.hasNext()) { GHRepository ghRepository = repoIterator.next(); String taskCategoryName = StringUtils .lowerCase(ACTaskCategory.REPOSITORY_PREFIX + ghRepository.getName()); if (taskCategoriesNames.contains(taskCategoryName)) repoIterator.remove(); } for (GHRepository ghRepository : repositoriesToCreateTaskCategoriesFor) { String taskCategoryToCreateName = ACTaskCategory.REPOSITORY_PREFIX + getName(); if (taskCategoriesNames .contains(StringUtils.lowerCase(taskCategoryToCreateName)) == false) { ACCategory acCategory = new ACCategory(); acCategory.setName(taskCategoryToCreateName); changedObjects.add(ACTaskCategory.process( ACCategory.create(acCategory, getId(), ACTaskCategory.class), getId(), true)); } } } catch (IOException ex) { throw new SyncActionError(ex, changedObjects); } return changedObjects; } @Override public Collection<String> getPropertyDescriptorNamesTicked() { return tickedDescriptors; } @Override public SyncEvent getOriginatingSyncEvent() { return syncEvent; } @Override public Collection<DSIObject> getSyncDependedDSIObjects() { return Collections.emptySet(); } @Override public Set<Class> getSyncDependedTypesOfDSIObjects() { return Collections.emptySet(); } }; } }