// Bug.java // package er.bugtracker; import java.util.Enumeration; import com.webobjects.eoaccess.EODatabaseDataSource; import com.webobjects.eocontrol.EOEditingContext; import com.webobjects.eocontrol.EOFetchSpecification; import com.webobjects.eocontrol.EOKeyValueQualifier; import com.webobjects.eocontrol.EONotQualifier; import com.webobjects.eocontrol.EOOrQualifier; import com.webobjects.eocontrol.EOQualifier; import com.webobjects.eocontrol.EOSortOrdering; import com.webobjects.foundation.NSArray; import com.webobjects.foundation.NSMutableArray; import com.webobjects.foundation.NSTimestamp; import com.webobjects.foundation.NSValidation; import er.corebusinesslogic.ERCoreBusinessLogic; import er.extensions.eof.ERXEC; import er.extensions.eof.ERXEOControlUtilities; import er.extensions.foundation.ERXArrayUtilities; import er.taggable.ERTaggable; public class Bug extends _Bug implements Markable { protected boolean _componentChanged; protected boolean _ownerChanged; @Override public void init(EOEditingContext ec) { super.init(ec); setPriority(Priority.MEDIUM); setState(State.ANALYZE); setTargetRelease(Release.clazz.defaultRelease(ec)); setIsRead(true); setIsFeatureRequest(false); setOriginator(People.clazz.currentUser(editingContext())); setOwner(People.clazz.currentUser(editingContext())); setDateSubmitted(new NSTimestamp()); setDateModified(new NSTimestamp()); Comment comment = Comment.clazz.createAndInsertObject(ec); comment.setOriginator(originator()); comment.setBug(this); } public ERTaggable<Bug> taggable() { return ERTaggable.taggable(this); } public void markAsRead() { EOEditingContext ec = ERXEC.newEditingContext(); ec.lock(); try { People people = (People) ERCoreBusinessLogic.actor(ec); Bug copy = ERXEOControlUtilities.localInstanceOfObject(ec, this); if(copy != null && !copy.isRead() && copy.owner().equals(people)) { copy.setIsRead(true); ec.saveChanges(); } } finally { ec.unlock(); } } public void markUnread() { setIsRead(false); } public void touch() { markUnread(); setDateModified(new NSTimestamp()); } public NSArray commentsByDate() { NSArray comments = comments(); comments = (NSArray) comments.valueForKeyPath("@sortAsc." + Comment.Key.DATE_SUBMITTED); return comments; } private Comment firstComment() { return (Comment) commentsByDate().objectAtIndex(0); } public String textDescription() { return firstComment().textDescription(); } public void setTextDescription(String value) { firstComment().setTextDescription(value); } // FIXME:(ak) now *what* is this supposed to do??? @Override public void setComponent(Component value) { willChange(); Component oldComponent = component(); super.setComponent(value); if (value!=null) { if (owner() == null) { setOwner(component().owner()); } else if ((oldComponent==null) || (!(value.equals(oldComponent)))) { _componentChanged = true; } } } @Override public void setOwner(People value) { willChange(); People oldOwner = owner(); super.setOwner(value); People currentUser = People.clazz.currentUser(editingContext()); if ((value!=null) && (value!=currentUser) && (oldOwner==null || (!(value.equals(oldOwner))))) { _ownerChanged=true; if (oldOwner!=null) setPreviousOwner(oldOwner); touch(); } } @Override public void setState(State newState) { willChange(); State oldState = state(); if (newState==State.CLOSED && isFeatureRequest() && oldState==State.VERIFY) newState=State.DOCUMENT; super.setState(newState); if (newState==State.DOCUMENT && !_ownerChanged) { People documenter = People.clazz.defaultDocumenter(editingContext()); if(documenter!=null) { setOwner(documenter); setIsRead(false); } } if (newState==State.VERIFY && !_ownerChanged) { People verifier = People.clazz.defaultVerifier(editingContext()); if(verifier!=null) { setOwner(verifier); } else { setOwner(originator()); touch(); } } } public Object validateTargetReleaseForNewBugs() throws NSValidation.ValidationException { Release release = targetRelease(); if (release != null) { if (!release.isOpen()) throw new NSValidation.ValidationException("Sorry, the release <b>"+release.valueForKey("name")+"</b> is closed. Bugs/Requirements can only be attached to open releases" ); } return null; } @Override public void validateForInsert() { super.validateForInsert(); validateTargetReleaseForNewBugs(); } @Override public void validateForUpdate() { if (_componentChanged && component()!=null && !_ownerChanged) { setOwner(component().owner()); } _componentChanged=false; _ownerChanged=false; super.validateForUpdate(); if(!(changesFromCommittedSnapshot().count() == 1 && changesFromCommittedSnapshot().allKeys().containsObject(Key.IS_READ))) { touch(); } } public boolean canForDelete () { return false; } // this key is used during mass updates by both the template EO and the real bugs private String _newText; public String newText() { return _newText; } public void setNewText(String newValue) { _newText = newValue; if (newValue != null && newValue.length() > 0) { Comment comment = Comment.clazz.createAndInsertObject(editingContext()); comment.setBug(this); comment.setTextDescription(newValue); addToComments(comment); touch(); } } public NSArray sortedComments() { return ERXArrayUtilities.sortedArraySortedWithKey(comments(), Comment.Key.DATE_SUBMITTED); } @Override public void didUpdate() { super.didUpdate(); _newText=null; } // Class methods go here public static class BugClazz<Bug> extends _BugClazz { protected EOQualifier qualifierForRelease(Release release) { if(release != null) { return new EOKeyValueQualifier(Key.TARGET_RELEASE, EOQualifier.QualifierOperatorEqual, release); } return null; } protected EOQualifier qualifierForState(State state) { if(state != null) { return new EOKeyValueQualifier(Key.STATE, EOQualifier.QualifierOperatorEqual, state); } return null; } protected EOQualifier qualifierForStates(State states[]) { return ERXEOControlUtilities.orQualifierForKeyPaths( new NSArray(Key.STATE), EOQualifier.QualifierOperatorEqual, new NSArray(states) ); } protected EOQualifier qualifierForOwner(People owner) { if(owner != null) { return new EOKeyValueQualifier(Key.OWNER, EOQualifier.QualifierOperatorEqual, owner); } return null; } protected EOQualifier qualifierForRead(boolean flag) { return new EOKeyValueQualifier(Key.IS_READ, EOQualifier.QualifierOperatorEqual, Boolean.valueOf(flag)); } protected EOQualifier qualifierForPerson(People owner) { return ERXEOControlUtilities.orQualifier( new EOKeyValueQualifier(Key.OWNER, EOQualifier.QualifierOperatorEqual, owner), new EOKeyValueQualifier(Key.ORIGINATOR, EOQualifier.QualifierOperatorEqual, owner) ); } protected EOQualifier negateQualifier(EOQualifier qualifier) { if(qualifier != null) { qualifier = new EONotQualifier(qualifier); } return qualifier; } protected EOQualifier andQualifier(EOQualifier q1, EOQualifier q2) { return ERXEOControlUtilities.andQualifier(q1, q2); } protected EOQualifier ordQualifier(EOQualifier q1, EOQualifier q2) { return ERXEOControlUtilities.orQualifier(q1, q2); } protected EOFetchSpecification newFetchSpecification(EOQualifier qualifier) { return new EOFetchSpecification(entityName(), qualifier, null); } protected EOFetchSpecification newFetchSpecification(EOQualifier qualifier, NSArray sorting) { return new EOFetchSpecification(entityName(), qualifier, sorting); } public EOFetchSpecification fetchSpecificationForOwnedBugs(People people) { // owner, not(closed) EOFetchSpecification fs = newFetchSpecification( andQualifier( qualifierForOwner(people), negateQualifier(qualifierForState(State.CLOSED)))); return fs; } public NSArray bugsOwnedWithUser(EOEditingContext context, People people) { return context.objectsWithFetchSpecification(fetchSpecificationForOwnedBugs(people)); } public NSArray unreadBugsWithUser(EOEditingContext context, People people) { // owner or originator, not(read) EOFetchSpecification fs = newFetchSpecification( andQualifier( qualifierForPerson(people), qualifierForRead(false))); return context.objectsWithFetchSpecification(fs); } public NSArray bugsInBuildWithTargetRelease(EOEditingContext context, Release targetRelease) { // release, build EOFetchSpecification fs = newFetchSpecification( andQualifier( qualifierForRelease(targetRelease), qualifierForState(State.BUILD))); return context.objectsWithFetchSpecification(fs); } public NSArray openBugsWithTargetRelease(EOEditingContext context, Release targetRelease) { // release, build EOFetchSpecification fs = newFetchSpecification( andQualifier( qualifierForRelease(targetRelease), negateQualifier(qualifierForState(State.CLOSED)))); return context.objectsWithFetchSpecification(fs); } public NSArray findBugs(EOEditingContext ec, String string) { NSArray a=NSArray.componentsSeparatedByString(string," "); NSMutableArray quals=new NSMutableArray(); for (Enumeration e=a.objectEnumerator(); e.hasMoreElements();) { String s=(String)e.nextElement(); try { Integer i = Integer.valueOf(s); quals.addObject(new EOKeyValueQualifier("id", EOQualifier.QualifierOperatorEqual, i)); } catch (NumberFormatException ex) {} } EOOrQualifier or=new EOOrQualifier(quals); EODatabaseDataSource ds=newDatabaseDataSource(ec); EOFetchSpecification fs=newFetchSpecification(or,null); ds.setFetchSpecification(fs); NSArray bugs = ds.fetchObjects(); return bugs; } public EOFetchSpecification fetchSpecificationForRecentBugs() { EOFetchSpecification fs = newFetchSpecification( andQualifier( new EOKeyValueQualifier(Key.DATE_MODIFIED, EOQualifier.QualifierOperatorGreaterThan, new NSTimestamp().timestampByAddingGregorianUnits(0, -1, 0, 0, 0, 0)), negateQualifier(qualifierForState(State.CLOSED)))); fs.setSortOrderings(new NSArray(new EOSortOrdering(Key.DATE_MODIFIED, EOSortOrdering.CompareDescending))); fs.setIsDeep(false); return fs; } public NSArray allBugsForUser(EOEditingContext context, People people) { EOFetchSpecification fs = newFetchSpecification( qualifierForOwner(people)); return context.objectsWithFetchSpecification(fs); } } public static final BugClazz<Bug> clazz = new BugClazz<>(); public void close() { setState(State.CLOSED); } public void reopen() { setState(State.ANALYZE); setOwner(previousOwner()); } public void rejectVerification() { setState(State.ANALYZE); setOwner(previousOwner()); } public void moveToVerification() { setState(State.VERIFY); } public Number bugid() { return (Number) rawPrimaryKey(); } public Number id() { return (Number) rawPrimaryKey(); } }