Java tutorial
/* * @(#)Accountability.java * * Copyright 2009 Instituto Superior Tecnico * Founding Authors: Joo Figueiredo, Luis Cruz * * https://fenix-ashes.ist.utl.pt/ * * This file is part of the Organization Module. * * The Organization Module is free software: you can * redistribute it and/or modify it under the terms of the GNU Lesser General * Public License as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * The Organization Module is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the Organization Module. If not, see <http://www.gnu.org/licenses/>. * */ package module.organization.domain; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import jvstm.cps.ConsistencyPredicate; import module.organization.domain.predicates.PartyPredicate.PartyByAccTypeAndDates; import org.fenixedu.bennu.core.domain.Bennu; import org.fenixedu.bennu.core.domain.User; import org.fenixedu.bennu.core.domain.exceptions.DomainException; import org.joda.time.DateTime; import org.joda.time.LocalDate; import pt.ist.fenixframework.Atomic; /** * * @author Joo Antunes * @author Joo Neves * @author Joo Figueiredo * @author Paulo Abrantes * @author Luis Cruz * @author Susana Fernandes * */ public class Accountability extends Accountability_Base { protected static final String LOCAL_DATE_FORMAT = "yyyy-MM-dd"; public static final Comparator<Accountability> COMPARATOR_BY_PARENT_PARTY_NAMES = new Comparator<Accountability>() { @Override public int compare(final Accountability o1, final Accountability o2) { final int c = Party.COMPARATOR_BY_NAME.compare(o1.getParent(), o2.getParent()); return c == 0 ? o1.getExternalId().compareTo(o2.getExternalId()) : c; } }; public static final Comparator<Accountability> COMPARATOR_BY_CHILD_PARTY_NAMES = new Comparator<Accountability>() { @Override public int compare(final Accountability o1, final Accountability o2) { final int c = Party.COMPARATOR_BY_NAME.compare(o1.getChild(), o2.getChild()); return c == 0 ? o1.getExternalId().compareTo(o2.getExternalId()) : c; } }; public static final Comparator<Accountability> COMPARATOR_BY_CREATION_DATE_FALLBACK_TO_START_DATE = new Comparator<Accountability>() { @Override public int compare(final Accountability o1, final Accountability o2) { DateTime o1CreationDate = o1.getCreationDate(); DateTime o2CreationDate = o2.getCreationDate(); if (o1CreationDate == null) { o1CreationDate = o1.getBeginDate().toDateTimeAtStartOfDay(); } if (o2CreationDate == null) { o2CreationDate = o2.getBeginDate().toDateTimeAtStartOfDay(); } return (o1CreationDate.compareTo(o2CreationDate)) == 0 ? (o1.getExternalId().compareTo(o2.getExternalId())) : (o1CreationDate.compareTo(o2CreationDate)); }; }; protected Accountability() { super(); setMyOrg(Bennu.getInstance()); } protected Accountability(final Party parent, final Party child, final AccountabilityType type, final LocalDate begin, final LocalDate end, String justification) { this(); check(parent, "error.Accountability.invalid.parent"); check(child, "error.Accountability.invalid.child"); check(type, "error.Accountability.invalid.type"); check(begin, "error.Accountability.invalid.begin"); checkDates(parent, begin, end); canCreate(parent, child, type); init(parent, child, type); editDates(begin, end, justification); } protected void init(Party parent, Party child, AccountabilityType type) { super.setParent(parent); super.setChild(child); super.setAccountabilityType(type); } protected void checkDates(final Party parent, final LocalDate begin, final LocalDate end) { if (begin != null && end != null && begin.isAfter(end)) { throw new OrganizationDomainException("error.Accountability.begin.is.after.end"); } checkBeginFromOldestParentAccountability(parent, begin); } private void checkBeginFromOldestParentAccountability(final Party parent, final LocalDate begin) throws DomainException { Accountability oldest = null; for (final Accountability accountability : parent.getParentAccountabilitiesSet()) { if (oldest == null || accountability.getBeginDate().isBefore(oldest.getBeginDate())) { oldest = accountability; } } if (oldest != null && begin.isBefore(oldest.getBeginDate())) { final String[] args = new String[] { oldest.getChild().getPartyName().getContent(), oldest.getBeginDate().toString("dd/MM/yyyy") }; throw new OrganizationDomainException("error.Accountability.begin.starts.before.oldest.parent.begin", args); } } protected void check(final Object obj, final String message) { if (obj == null) { throw new OrganizationDomainException(message); } } protected void canCreate(final Party parent, final Party child, final AccountabilityType type) { if (parent.equals(child)) { throw new OrganizationDomainException("error.Accountability.parent.equals.child"); } if (parent.ancestorsInclude(child, type)) { throw new OrganizationDomainException("error.Accountability.parent.ancestors.include.child.with.type"); } if (!type.isValid(parent, child)) { throw new OrganizationDomainException("error.Accountability.type.doesnot.allow.parent.child"); } } public boolean isValid() { return getParent() != null && getChild() != null && getAccountabilityType().isValid(getParent(), getChild()); } public boolean isActive(final LocalDate date) { return contains(date) && !isErased(); } /** * * @return true if the AccountabilityHistory item is inactive, false * otherwise */ public boolean isErased() { if (getAccountabilityVersion() == null) { return false; } return getAccountabilityVersion().getErased(); } public boolean isActiveNow() { final LocalDate now = new LocalDate(); return isActive(now); } public boolean contains(final LocalDate date) { return !getBeginDate().isAfter(date) && (!hasEndDate() || getEndDate().isAfter(date)); } public boolean contains(final LocalDate begin, final LocalDate end) { check(begin, "error.Accountability.intercepts.invalid.begin"); return (end == null || !getBeginDate().isAfter(end)) && (!hasEndDate() || !begin.isAfter(getEndDate())); } private boolean hasBeginDate() { return getBeginDate() != null; } private boolean hasEndDate() { return getEndDate() != null; } public boolean hasAccountabilityType(AccountabilityType type) { return getAccountabilityType().equals(type); } public String getDetailsString() { final StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(getAccountabilityType().getName().getContent()); stringBuilder.append(": "); if (getBeginDate() != null) { stringBuilder.append(getBeginDate().toString(LOCAL_DATE_FORMAT)); } stringBuilder.append(" - "); if (getEndDate() != null) { stringBuilder.append(getEndDate().toString(LOCAL_DATE_FORMAT)); } return stringBuilder.toString(); } /** * It doesn't actually delete the accountability as it actually marks it as an accountability history item * * @deprecated use {@link #delete(String)} instead */ @Deprecated public void delete() { setInactive(null); } /** * It doesn't actually delete the accountability as it actually marks it as an accountability history item * * @param justification an information justification/reason for the change of accountability, or null if there is none, or * none is provided */ @Atomic public void delete(String justification) { setInactive(justification); } static Accountability create(final Party parent, final Party child, final AccountabilityType type, final LocalDate begin, final LocalDate end, String justification) { // TODO Fenix-133: allow the access control to be done in a more dynamic // way, see issue for more info // return parent.isAuthorizedToManage() ? new Accountability(parent, // child, type, begin, end) // : new UnconfirmedAccountability(parent, child, type, begin, end); return new Accountability(parent, child, type, begin, end, justification); } @Override @Deprecated public void setParent(Party parent) { throw new OrganizationDomainException("should.not.use.this.method.delete.and.create.another.instead"); } @Override @Deprecated public void setChild(Party child) { throw new OrganizationDomainException("should.not.use.this.method.delete.and.create.another.instead"); } @Override @Deprecated public void setAccountabilityType(AccountabilityType accountabilityType) { throw new OrganizationDomainException("should.not.use.this.method.delete.and.create.another.instead"); } /** * * @param beginDate begin date * @param justification an information justification/reason for the change of accountability, or null if there is none, or * none is provided */ public void setBeginDate(LocalDate beginDate, String justification) { editDates(beginDate, getEndDate(), justification); } public void setBeginDate(LocalDate beginDate) { editDates(beginDate, getEndDate()); } /** * * @param endDate end date * @param justification an information justification/reason for the change of accountability, or null if there is none, or * none is provided */ public void setEndDate(LocalDate endDate, String justification) { editDates(getBeginDate(), endDate, justification); } public void setEndDate(LocalDate endDate) { editDates(getBeginDate(), endDate); } /** * Marks the current accountability as an historic one and creates a new one * based on the new dates * * @param begin * the new begin date * @param end * the new end date * @deprecated use the {@link #editDates(LocalDate, LocalDate, String)} instead */ @Deprecated public void editDates(final LocalDate begin, final LocalDate end) { editDates(begin, end, null); } /** * Marks the current accountability as an historic one and creates a new one * based on the new dates * * @param begin * the new begin date * @param end * the new end date * @param justification an information justification/reason for the change of accountability, or null if there is none, or * none is provided */ @Atomic public void editDates(final LocalDate begin, final LocalDate end, String justification) { check(begin, "error.Accountability.invalid.begin"); checkDates(getParent(), begin, end); // let's create the new AccountabilityHistory which is active AccountabilityVersion.insertAccountabilityVersion(begin, end, this, false, justification); } /* * NOTE: this method returns the interval between the 00:00 of the StartDate * and 23:59:59 of the EndDate * * @return the Interval between the begin and end date, or today if end date * is unspecified (null) public Interval getCurrentScope() { DateTime * endDate = (getEndDate() == null) ? new * LocalDate().plusDays(1).toDateTimeAtStartOfDay() : getEndDate().plusDays( * 1).toDateTimeAtStartOfDay(); DateTime beginDate = * getBeginDate().toDateTimeAtStartOfDay(); return new Interval(endDate, * beginDate); } */ private void setInactive(String justification) { AccountabilityVersion.insertAccountabilityVersion(getBeginDate(), getEndDate(), this, true, justification); } /** * * @param start start * @param end end * @return true if the given start and end date overlap in more than one day * with this accountability (exclusively, i.e. if the end date of * this accountability equals the begin date passed as argument, it * returns false) */ public boolean overlaps(final LocalDate start, final LocalDate end) { LocalDate startDateToUse = start == null ? start : start.plusDays(1); LocalDate endDateToUse = end == null ? end : end.minusDays(1); return intersects(startDateToUse, endDateToUse); } /** * * @param begin begin * @param end end * @return true if it intersects i.e. (TODO a better explanation of what it * means) it works inclusively e.g. if the end day and the start day * of the accountability are the same, it returns true */ public boolean intersects(final LocalDate begin, final LocalDate end) { return !isAfter(getBeginDate(), end) && !isAfter(begin, getEndDate()); } /** * * @param localDate1 localDate1 * @param localDate2 localDate2 * @return false if any of the dates are null, or if localDate1 isn't after * localDate2, true otherwise */ private static boolean isAfter(final LocalDate localDate1, final LocalDate localDate2) { return localDate1 != null && localDate2 != null && localDate2.isBefore(localDate1); } public static List<Accountability> getActiveAndInactiveAccountabilities(List<AccountabilityType> accTypes, List<Party> parties, LocalDate startDate, LocalDate endDate) { List<Accountability> accountabilities = new ArrayList<Accountability>(); // let's iterate through the parties for (Party party : parties) { accountabilities.addAll(party.getAccountabilitiesAndHistoricItems(accTypes, startDate, endDate)); } // if no parties have been specified, we will get all of the // accountabilities!! if (parties == null || parties.isEmpty()) { final PartyByAccTypeAndDates typeAndDates = new PartyByAccTypeAndDates(startDate, endDate, accTypes); for (final Accountability accountability : Bennu.getInstance().getAccountabilitiesSet()) { if (typeAndDates.eval(null, accountability)) { accountabilities.add(accountability); } } } Collections.sort(accountabilities, COMPARATOR_BY_CREATION_DATE_FALLBACK_TO_START_DATE); return accountabilities; } @ConsistencyPredicate public boolean checkHasChild() { return getChild() != null; } @ConsistencyPredicate public boolean checkHasParent() { return getParent() != null; } public LocalDate getBeginDate() { return getAccountabilityVersion().getBeginDate(); } public LocalDate getEndDate() { return getAccountabilityVersion().getEndDate(); } public String getJustification() { return getAccountabilityVersion().getJustification(); } public DateTime getCreationDate() { return getAccountabilityVersion().getCreationDate(); } public User getCreatorUser() { return getAccountabilityVersion().getUserWhoCreated(); } public void switchChild(final Party newChild) { super.setChild(newChild); } @Deprecated public java.util.Set<module.organization.domain.FunctionDelegation> getFunctionDelegationDelegated() { return getFunctionDelegationDelegatedSet(); } }