package eu.doppel_helix.netbeans.mantisintegration.issue; import biz.futureware.mantisconnect.AccountData; import biz.futureware.mantisconnect.AttachmentData; import biz.futureware.mantisconnect.CustomFieldValueForIssueData; import biz.futureware.mantisconnect.IssueData; import biz.futureware.mantisconnect.IssueNoteData; import biz.futureware.mantisconnect.ObjectRef; import biz.futureware.mantisconnect.RelationshipData; import eu.doppel_helix.netbeans.mantisintegration.data.Permission; import eu.doppel_helix.netbeans.mantisintegration.issue.serialization.IssueInfo; import eu.doppel_helix.netbeans.mantisintegration.repository.MantisRepository; import eu.doppel_helix.netbeans.mantisintegration.util.SafeAutocloseable; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.File; import java.io.IOException; import java.math.BigInteger; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.logging.Logger; import javax.xml.rpc.ServiceException; import org.netbeans.modules.bugtracking.spi.IssueProvider; import org.netbeans.modules.bugtracking.spi.IssueStatusProvider; import org.openide.util.Mutex; public class MantisIssue { private final static Logger logger = Logger.getLogger(MantisIssue.class.getName()); private final MantisRepository mr; private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); private final IssueData issueData = new IssueData(); private MantisIssueController mic; private Integer busy = 0; private Permission timetracking = Permission.NONE; private final SafeAutocloseable busyHelper = new SafeAutocloseable() { @Override public void close() { setBusy(false); } }; public SafeAutocloseable busy() { setBusy(true); return busyHelper; } public MantisIssue(MantisRepository mr) { this.mr = mr; } // Convenience methods public boolean isBusy() { return busy != 0; } private void setBusy(boolean busyBool) { boolean oldBusy = isBusy(); synchronized(this) { if (busyBool) { busy++; } else { busy--; } if (busy < 0) { throw new IllegalStateException("Inbalanced busy/nonbusy"); } } firePropertyChange("busy", oldBusy, isBusy()); } public void setIdFromString(String id) { String oldValue = getIdAsString(); if (id == null) { setId(null); } else { setId(new BigInteger(id)); } firePropertyChange("idFromString", oldValue, getIdAsString()); } public String getIdAsString() { BigInteger result = this.issueData.getId(); if (result == null) { return null; } else { return result.toString(); } } public String getDisplayValue() { if (getId() == null) { return "New Issue"; } else { return "#" + getIdAsString() + " - " + getSummary(); } } public List<String> getSubtasks() { List<String> result = new ArrayList<>(); for (RelationshipData rd : getRelationships()) { if (rd.getType().getId().intValue() == 2) { result.add(rd.getTarget_id().toString()); } } return result; } public boolean refresh() throws ServiceException, RemoteException { try (SafeAutocloseable ac = busy()) { boolean result = mr.updateIssueFromRepository(MantisIssue.this); timetracking = mr.getCapabilities().getTrackTime(this); if (result) { firePropertyChange(IssueProvider.EVENT_ISSUE_DATA_CHANGED, null, null); } return result; } } public void updateFromIssueData(final IssueData id) { issueData.setId(id.getId()); issueData.setView_state(id.getView_state()); issueData.setLast_updated(id.getLast_updated()); issueData.setProject(id.getProject()); issueData.setCategory(id.getCategory()); issueData.setPriority(id.getPriority()); issueData.setSeverity(id.getSeverity()); issueData.setStatus(id.getStatus()); issueData.setReporter(id.getReporter()); issueData.setSummary(id.getSummary()); issueData.setVersion(id.getVersion()); issueData.setBuild(id.getBuild()); issueData.setPlatform(id.getPlatform()); issueData.setOs(id.getOs()); issueData.setOs_build(id.getOs_build()); issueData.setReproducibility(id.getReproducibility()); issueData.setDate_submitted(id.getDate_submitted()); issueData.setSponsorship_total(id.getSponsorship_total()); issueData.setHandler(id.getHandler()); issueData.setProjection(id.getProjection()); issueData.setEta(id.getEta()); issueData.setResolution(id.getResolution()); issueData.setFixed_in_version(id.getFixed_in_version()); issueData.setDescription(id.getDescription()); issueData.setSteps_to_reproduce(id.getSteps_to_reproduce()); issueData.setAdditional_information(id.getAdditional_information()); issueData.setAttachments(id.getAttachments()); issueData.setRelationships(id.getRelationships()); issueData.setNotes(id.getNotes()); issueData.setCustom_fields(id.getCustom_fields()); issueData.setTags(id.getTags()); issueData.setTarget_version(id.getTarget_version()); issueData.setVersion(id.getVersion()); Mutex.EVENT.writeAccess(new Runnable() { @Override public void run() { firePropertyChange(IssueProvider.EVENT_ISSUE_DATA_CHANGED, null, null); } }); } public MantisIssueController getController() { if (mic == null) { mic = new MantisIssueController(this); } return mic; } public boolean isFinished() { // @todo: Respect settings of repository // Current implemention: isFinished = Status.ID >= 80 return BigInteger.valueOf(80).compareTo(issueData.getStatus().getId()) <= 0; } public void attachFile(File file, String description) throws ServiceException, RemoteException, IOException { try (SafeAutocloseable ac = busy()) { mr.addFile(this, file, description); } } public void addComment(String comment, boolean closeAsFixed) throws ServiceException, RemoteException { try (SafeAutocloseable ac = busy()) { mr.addComment(this, comment, null, null); if(closeAsFixed) { if(mr.getCommitStatus() != null) { this.setStatus(mr.getCommitStatus()); } if(mr.getCommitResolution() != null) { this.setResolution(mr.getCommitResolution()); } mr.updateIssue(this, getIssueData()); } } } public MantisRepository getMantisRepository() { return mr; } public IssueData getIssueData() { return this.issueData; } public void removeRelationship(RelationshipData rd) throws ServiceException, RemoteException { try (SafeAutocloseable ac = busy()) { mr.removeRelationship(this, rd); } } public void removeFile(AttachmentData ad) throws ServiceException, RemoteException { try (SafeAutocloseable ac = busy()) { mr.removeFile(this, ad); } } public byte[] getFile(AttachmentData ad) throws ServiceException, RemoteException { try (SafeAutocloseable ac = busy()) { return mr.getFile(this, ad); } } public void addFile(File f, String comment) throws ServiceException, RemoteException, IOException { try (SafeAutocloseable ac = busy()) { mr.addFile(this, f, comment); } } public void addComment(String comment, ObjectRef viewState, BigInteger timetracking) throws ServiceException, RemoteException { try (SafeAutocloseable ac = busy()) { mr.addComment(this, comment, viewState, timetracking); } } public void addRelationship(ObjectRef type, BigInteger target) throws ServiceException, RemoteException { try (SafeAutocloseable ac = busy()) { mr.addRelationship(this, type, target); } } public void addTag(String... tagString) throws ServiceException, RemoteException { try (SafeAutocloseable ac = busy()) { mr.addTag(this, tagString); } } public void removeTag(ObjectRef... tag) throws ServiceException, RemoteException { try (SafeAutocloseable ac = busy()) { mr.removeTag(this, tag); } } public int getNoteCount() { if (issueData.getNotes() == null) { return 0; } else { return issueData.getNotes().length; } } /** * Check whether update of issue data and tags is possible * * @todo: Implement a better strategy to check */ public boolean canUpdate() { return mr.getCapabilities().canUpdate(this); } public Permission getTimetracking() { return timetracking; } // Property change support public void addPropertyChangeListener(PropertyChangeListener listener) { pcs.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { pcs.removePropertyChangeListener(listener); } protected void firePropertyChange(final String property, final Object oldValue, final Object newValue) { Mutex.EVENT.writeAccess(new Runnable() { @Override public void run() { pcs.firePropertyChange(property, oldValue, newValue); } }); } // Delegation to IssueData including property change support public BigInteger getId() { return issueData.getId(); } public void setId(BigInteger id) { BigInteger oldValue = issueData.getId(); String oldDisplayValue = getDisplayValue(); issueData.setId(id); firePropertyChange("id", oldValue, id); firePropertyChange("displayValue", oldDisplayValue, getDisplayValue()); } public ObjectRef getView_state() { return issueData.getView_state(); } public void setView_state(ObjectRef view_state) { ObjectRef oldValue = issueData.getView_state(); issueData.setView_state(view_state); firePropertyChange("view_state", oldValue, view_state); } public Calendar getLast_updated() { return issueData.getLast_updated(); } public void setLast_updated(Calendar last_updated) { Calendar oldValue = issueData.getLast_updated(); issueData.setLast_updated(last_updated); firePropertyChange("last_updated", oldValue, last_updated); } public ObjectRef getProject() { return issueData.getProject(); } public void setProject(ObjectRef project) { ObjectRef oldValue = issueData.getProject(); issueData.setProject(project); firePropertyChange("project", oldValue, project); } public String getCategory() { return issueData.getCategory(); } public void setCategory(String category) { String oldValue = issueData.getCategory(); issueData.setCategory(category); firePropertyChange("category", oldValue, category); } public ObjectRef getPriority() { return issueData.getPriority(); } public void setPriority(ObjectRef priority) { ObjectRef oldValue = issueData.getPriority(); issueData.setPriority(priority); firePropertyChange("priority", oldValue, priority); } public ObjectRef getSeverity() { return issueData.getSeverity(); } public void setSeverity(ObjectRef severity) { ObjectRef oldValue = issueData.getSeverity(); issueData.setSeverity(severity); firePropertyChange("severity", oldValue, severity); } public ObjectRef getStatus() { return issueData.getStatus(); } public void setStatus(ObjectRef status) { ObjectRef oldValue = issueData.getStatus(); issueData.setStatus(status); firePropertyChange("status", oldValue, status); } public AccountData getReporter() { return issueData.getReporter(); } public void setReporter(AccountData reporter) { AccountData oldValue = issueData.getReporter(); issueData.setReporter(reporter); firePropertyChange("reporter", oldValue, reporter); } public String getSummary() { return issueData.getSummary(); } public void setSummary(String summary) { String oldValue = issueData.getSummary(); String oldDisplayValue = getDisplayValue(); issueData.setSummary(summary); firePropertyChange("summary", oldValue, summary); firePropertyChange("displayValue", oldDisplayValue, getDisplayValue()); } public String getVersion() { return issueData.getVersion(); } public void setVersion(String version) { String oldValue = issueData.getVersion(); issueData.setVersion(version); firePropertyChange("version", oldValue, version); } public String getBuild() { return issueData.getBuild(); } public void setBuild(String build) { String oldValue = issueData.getBuild(); issueData.setBuild(build); firePropertyChange("build", oldValue, build); } public String getPlatform() { return issueData.getPlatform(); } public void setPlatform(String platform) { String oldValue = issueData.getPlatform(); issueData.setPlatform(platform); firePropertyChange("platform", oldValue, platform); } public String getOs() { return issueData.getOs(); } public void setOs(String os) { String oldValue = issueData.getOs(); issueData.setOs(os); firePropertyChange("os", oldValue, os); } public String getOs_build() { return issueData.getOs_build(); } public void setOs_build(String os_build) { String oldValue = issueData.getOs_build(); issueData.setOs_build(os_build); firePropertyChange("os_build", oldValue, os_build); } public ObjectRef getReproducibility() { return issueData.getReproducibility(); } public void setReproducibility(ObjectRef reproducibility) { ObjectRef oldValue = issueData.getReproducibility(); issueData.setReproducibility(reproducibility); firePropertyChange("reproducibility", oldValue, reproducibility); } public Calendar getDate_submitted() { return issueData.getDate_submitted(); } public void setDate_submitted(Calendar date_submitted) { Calendar oldValue = issueData.getDate_submitted(); issueData.setDate_submitted(date_submitted); firePropertyChange("date_submitted", oldValue, date_submitted); } public BigInteger getSponsorship_total() { return issueData.getSponsorship_total(); } public void setSponsorship_total(BigInteger sponsorship_total) { BigInteger oldValue = issueData.getSponsorship_total(); issueData.setSponsorship_total(sponsorship_total); firePropertyChange("sponsorship_total", oldValue, sponsorship_total); } public AccountData getHandler() { return issueData.getHandler(); } public void setHandler(AccountData handler) { AccountData oldValue = issueData.getHandler(); issueData.setHandler(handler); firePropertyChange("handler", oldValue, handler); } public ObjectRef getProjection() { return issueData.getProjection(); } public void setProjection(ObjectRef projection) { ObjectRef oldValue = issueData.getProjection(); issueData.setProjection(projection); firePropertyChange("projection", oldValue, projection); } public ObjectRef getEta() { return issueData.getEta(); } public void setEta(ObjectRef eta) { ObjectRef oldValue = issueData.getEta(); issueData.setEta(eta); firePropertyChange("eta", oldValue, eta); } public ObjectRef getResolution() { return issueData.getResolution(); } public void setResolution(ObjectRef resolution) { ObjectRef oldValue = issueData.getResolution(); issueData.setResolution(resolution); firePropertyChange("resolution", oldValue, resolution); } public String getFixed_in_version() { return issueData.getFixed_in_version(); } public void setFixed_in_version(String fixed_in_version) { String oldValue = issueData.getFixed_in_version(); issueData.setFixed_in_version(fixed_in_version); firePropertyChange("fixed_in_version", oldValue, fixed_in_version); } public String getDescription() { return issueData.getDescription(); } public void setDescription(String description) { String oldValue = issueData.getDescription(); issueData.setDescription(description); firePropertyChange("description", oldValue, description); } public String getSteps_to_reproduce() { return issueData.getSteps_to_reproduce(); } public void setSteps_to_reproduce(String steps_to_reproduce) { String oldValue = issueData.getSteps_to_reproduce(); issueData.setSteps_to_reproduce(steps_to_reproduce); firePropertyChange("steps_to_reproduce", oldValue, steps_to_reproduce); } public String getAdditional_information() { return issueData.getAdditional_information(); } public void setAdditional_information(String additional_information) { String oldValue = issueData.getAdditional_information(); issueData.setAdditional_information(additional_information); firePropertyChange("additional_information", oldValue, additional_information); } public AttachmentData[] getAttachments() { return issueData.getAttachments(); } public void setAttachments(AttachmentData[] attachments) { AttachmentData[] oldValue = issueData.getAttachments(); issueData.setAttachments(attachments); firePropertyChange("attachments", oldValue, attachments); } public RelationshipData[] getRelationships() { return issueData.getRelationships(); } public void setRelationships(RelationshipData[] relationships) { RelationshipData[] oldValue = issueData.getRelationships(); issueData.setRelationships(relationships); firePropertyChange("relationships", oldValue, relationships); } public IssueNoteData[] getNotes() { return issueData.getNotes(); } public void setNotes(IssueNoteData[] notes) { IssueNoteData[] oldValue = issueData.getNotes(); issueData.setNotes(notes); firePropertyChange("notes", oldValue, notes); } public CustomFieldValueForIssueData[] getCustom_fields() { CustomFieldValueForIssueData[] value = issueData.getCustom_fields(); if(value == null) { value = new CustomFieldValueForIssueData[0]; } return value; } public void setCustom_fields(CustomFieldValueForIssueData[] custom_fields) { if(custom_fields == null) { custom_fields = new CustomFieldValueForIssueData[0]; } CustomFieldValueForIssueData[] oldValue = issueData.getCustom_fields(); issueData.setCustom_fields(custom_fields); firePropertyChange("custom_fields", oldValue, custom_fields); } public String getTarget_version() { return issueData.getTarget_version(); } public void setTarget_version(String version) { String oldValue = issueData.getTarget_version(); issueData.setTarget_version(version); firePropertyChange("target_version", oldValue, version); } public ObjectRef[] getTags() { return issueData.getTags(); } public void setTags(ObjectRef[] tags) { ObjectRef[] oldValue = issueData.getTags(); issueData.setTags(tags); firePropertyChange("tags", oldValue, tags); } public IssueStatusProvider.Status getReadStatus() { Date readDate = getReadDate(); if (readDate == null) { return IssueStatusProvider.Status.INCOMING_NEW; } else if (getLast_updated().getTime().after(readDate)) { return IssueStatusProvider.Status.INCOMING_MODIFIED; } else { return IssueStatusProvider.Status.SEEN; } } public Date getReadDate() { IssueInfo ii = getMantisRepository().getIssueInfosHandler().getIssueInfo(getId()); if (ii == null) { return null; } else { return ii.getReadState(); } } public void setRead(boolean read) { IssueInfo ii = getMantisRepository().getIssueInfosHandler().getIssueInfo(getId()); if (ii == null) { ii = new IssueInfo(getId()); } if (read) { ii.setReadState(new Date()); } else { ii.setReadState(null); } getMantisRepository().getIssueInfosHandler().putIssueInfo(ii); firePropertyChange(IssueStatusProvider.EVENT_STATUS_CHANGED, null, null); } }