package eu.doppel_helix.netbeans.mantisintegration.repository; import biz.futureware.mantisconnect.AccountData; import biz.futureware.mantisconnect.CustomFieldDefinitionData; import biz.futureware.mantisconnect.FilterData; import biz.futureware.mantisconnect.MantisConnectPortType; import biz.futureware.mantisconnect.ObjectRef; import biz.futureware.mantisconnect.ProjectData; import biz.futureware.mantisconnect.ProjectVersionData; import biz.futureware.mantisconnect.TagData; import eu.doppel_helix.netbeans.mantisintegration.util.StringUtils; import java.math.BigInteger; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.TreeSet; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.rpc.ServiceException; public class MasterData { private static final Logger LOG = Logger.getLogger(MasterData.class.getName()); private final MantisRepository mr; private ObjectRef[] priorities; private ObjectRef[] states; private ObjectRef[] resolutions; private ObjectRef[] reproducibilities; private ObjectRef[] viewStates; private ObjectRef[] severities; private ObjectRef[] projections; private ObjectRef[] etas; private ObjectRef[] customFieldTypes; private HashMap<BigInteger, ProjectData> projects; private HashMap<BigInteger, TagData> tags; // Hardcoded, as no api exists to retrieve this info private final ObjectRef[] relationships = new ObjectRef[]{ new ObjectRef(new BigInteger("0"), "duplicate of"), new ObjectRef(new BigInteger("1"), "related to"), new ObjectRef(new BigInteger("2"), "parent of"), new ObjectRef(new BigInteger("3"), "child of"), new ObjectRef(new BigInteger("4"), "has duplicate"),}; private final HashMap<BigInteger, String[]> categories = new HashMap<>(); private final HashMap<BigInteger, AccountData[]> users = new HashMap<>(); private final HashMap<BigInteger, ProjectVersionData[]> versions = new HashMap<>(); private final HashMap<BigInteger, FilterData[]> filters = new HashMap<>(); private final HashMap<BigInteger, CustomFieldDefinitionData[]> customFieldDefinitions = new HashMap<>(); public MasterData(MantisRepository mr) { this.mr = mr; } public ObjectRef[] getPriorities() throws ServiceException, RemoteException { if (priorities == null) { MantisConnectPortType mcpt = mr.getClient(); priorities = mcpt.mc_enum_priorities( mr.getInfo().getUsername(), new String(mr.getInfo().getPassword())); } return priorities; } public ObjectRef[] getRelationships() { return relationships; } public ObjectRef[] getStates() throws ServiceException, RemoteException { if (states == null) { MantisConnectPortType mcpt = mr.getClient(); states = mcpt.mc_enum_status( mr.getInfo().getUsername(), new String(mr.getInfo().getPassword())); } return states; } public ObjectRef[] getResolutions() throws RemoteException, ServiceException { if (resolutions == null) { MantisConnectPortType mcpt = mr.getClient(); ObjectRef[] resolutionsBuiltin = mcpt.mc_enum_resolutions( mr.getInfo().getUsername(), new String(mr.getInfo().getPassword())); ObjectRef[] res2 = new ObjectRef[resolutionsBuiltin.length + 1]; System.arraycopy(resolutionsBuiltin, 0, res2, 0, resolutionsBuiltin.length); res2[resolutionsBuiltin.length] = new ObjectRef(new BigInteger("-1"), "test"); resolutions = res2; } return resolutions; } public ObjectRef[] getReproducibilities() throws ServiceException, RemoteException { if (reproducibilities == null) { MantisConnectPortType mcpt = mr.getClient(); reproducibilities = mcpt.mc_enum_reproducibilities( mr.getInfo().getUsername(), new String(mr.getInfo().getPassword())); } return reproducibilities; } public ObjectRef[] getViewStates() throws ServiceException, RemoteException { if (viewStates == null) { MantisConnectPortType mcpt = mr.getClient(); viewStates = mcpt.mc_enum_view_states( mr.getInfo().getUsername(), new String(mr.getInfo().getPassword())); } return viewStates; } public ObjectRef[] getSeverities() throws ServiceException, RemoteException { if (severities == null) { MantisConnectPortType mcpt = mr.getClient(); severities = mcpt.mc_enum_severities( mr.getInfo().getUsername(), new String(mr.getInfo().getPassword())); } return severities; } public ObjectRef[] getProjections() throws ServiceException, RemoteException { if (projections == null) { MantisConnectPortType mcpt = mr.getClient(); projections = mcpt.mc_enum_projections( mr.getInfo().getUsername(), new String(mr.getInfo().getPassword())); } return projections; } public ObjectRef[] getEtas() throws ServiceException, RemoteException { if (etas == null) { MantisConnectPortType mcpt = mr.getClient(); etas = mcpt.mc_enum_etas( mr.getInfo().getUsername(), new String(mr.getInfo().getPassword())); } return etas; } private void initProjectList() throws ServiceException, RemoteException { if (projects == null) { MantisConnectPortType mcpt = mr.getClient(); projects = new HashMap<>(); ProjectData[] projectList = mcpt.mc_projects_get_user_accessible( mr.getInfo().getUsername(), new String(mr.getInfo().getPassword())); for (ProjectData pd : projectList) { projects.put(pd.getId(), pd); } } } public ProjectData getProject(BigInteger id) throws ServiceException, RemoteException { initProjectList(); return projects.get(id); } public ProjectData[] getProjects() throws ServiceException, RemoteException { initProjectList(); Collection<ProjectData> projectCollection = projects.values(); return projectCollection.toArray(new ProjectData[projectCollection.size()]); } public String[] getCategories(BigInteger projectID) throws ServiceException, RemoteException { String[] result = categories.get(projectID); if (result == null) { MantisConnectPortType mcpt = mr.getClient(); if (BigInteger.ZERO.equals(projectID)) { TreeSet<String> categoriesSet = new TreeSet<>(); for (ProjectData pd : getProjects()) { String[] projCategories = mcpt.mc_project_get_categories( mr.getInfo().getUsername(), new String(mr.getInfo().getPassword()), pd.getId()); categoriesSet.addAll(Arrays.asList(projCategories)); } categories.put(projectID, categoriesSet.toArray(new String[0])); } else { String[] projCategories = mcpt.mc_project_get_categories( mr.getInfo().getUsername(), new String(mr.getInfo().getPassword()), projectID); categories.put(projectID, projCategories); } } return categories.get(projectID); } public AccountData[] getUsers(BigInteger projectID) throws ServiceException, RemoteException { if (users.get(projectID) == null) { MantisConnectPortType mcpt = mr.getClient(); try { AccountData[] projCategories = mcpt.mc_project_get_users( mr.getInfo().getUsername(), new String(mr.getInfo().getPassword()), projectID, BigInteger.ONE); users.put(projectID, projCategories); } catch (RemoteException ex) { // @todo: Find a sane solution for the problem where the API // limits the usefulness (=> here mantis fails to return // user counts > approx. 15000 Users) LOG.log(Level.INFO, "", ex); users.put(projectID, new AccountData[0]); } } AccountData[] result = users.get(projectID); if (result == null) { result = new AccountData[0]; } return result; } public ProjectVersionData[] getVersions(BigInteger projectID) throws ServiceException, RemoteException { if (versions.get(projectID) == null) { MantisConnectPortType mcpt = mr.getClient(); try { ProjectVersionData[] projVersions = mcpt.mc_project_get_versions( mr.getInfo().getUsername(), new String(mr.getInfo().getPassword()), projectID); Arrays.sort(projVersions, new ProjectVersionDataComparator()); versions.put(projectID, projVersions); } catch (RemoteException ex) { LOG.log(Level.INFO, "", ex); versions.put(projectID, new ProjectVersionData[0]); } } ProjectVersionData[] result = versions.get(projectID); if (result == null) { result = new ProjectVersionData[0]; } return result; } public FilterData[] getFilters(BigInteger projectID) throws ServiceException, RemoteException { if (filters.get(projectID) == null) { MantisConnectPortType mcpt = mr.getClient(); FilterData[] fd = mcpt.mc_filter_get( mr.getInfo().getUsername(), new String(mr.getInfo().getPassword()), projectID); filters.put(projectID, fd); } return filters.get(projectID); } public ObjectRef[] getCustomFieldTypes(boolean enforceUpdate) throws ServiceException, RemoteException { if (enforceUpdate) { customFieldTypes = null; } if (customFieldTypes == null) { MantisConnectPortType mcpt = mr.getClient(); customFieldTypes = mcpt.mc_enum_custom_field_types( mr.getInfo().getUsername(), new String(mr.getInfo().getPassword())); } return customFieldTypes; } public CustomFieldDefinitionData[] getCustomFieldDefinitions(BigInteger projectID) throws ServiceException, RemoteException { if (customFieldDefinitions.get(projectID) == null) { MantisConnectPortType mcpt = mr.getClient(); CustomFieldDefinitionData[] cfds = mcpt.mc_project_get_custom_fields( mr.getInfo().getUsername(), new String(mr.getInfo().getPassword()), projectID); for (CustomFieldDefinitionData cfd : cfds) { if (cfd.getPossible_values().startsWith("=")) { String enumName = cfd.getPossible_values().substring(1).trim(); switch (enumName) { case "versions": cfd.setPossible_values(customFieldEnumVersions(projectID)); break; case "future_versions": cfd.setPossible_values(customFieldEnumVersionsReleased(projectID, false)); break; case "released_versions": cfd.setPossible_values(customFieldEnumVersionsReleased(projectID, true)); break; case "categories": cfd.setPossible_values(customFieldEnumCategories(projectID)); break; default: cfd.setType(BigInteger.valueOf(-1)); LOG.log(Level.WARNING, "Failed to calculate dynamic custom field mr.getInfo(). {0}", enumName); } } } customFieldDefinitions.put(projectID, cfds); } return customFieldDefinitions.get(projectID); } /** * Get a custom field definition by id. * * The function only accesses cached values, so it is save to be called on * the EDT. * * The idea: this is used to translate error messages when updating/setting * custom fields. At this point the definition has to be fetched already. * * @param id of custom field definition * @return the corresponding definition or null if definition was not found */ public CustomFieldDefinitionData getCustomFieldDefinition(BigInteger id) { Iterator<CustomFieldDefinitionData[]> it = customFieldDefinitions.values().iterator(); while (it.hasNext()) { CustomFieldDefinitionData[] cfds = it.next(); for (CustomFieldDefinitionData cfd : cfds) { if (id.equals(cfd.getField().getId())) { return cfd; } } } return null; } private String customFieldEnumCategories(BigInteger projectID) throws ServiceException, RemoteException { return StringUtils.toCustomFieldList(getCategories(projectID)); } private String customFieldEnumVersions(BigInteger projectID) throws ServiceException, RemoteException { List<String> list = new ArrayList<>(); for (ProjectVersionData pvd : getVersions(projectID)) { list.add(pvd.getName()); } Collections.sort(list); return StringUtils.toCustomFieldList(list); } private String customFieldEnumVersionsReleased(BigInteger projectID, boolean released) throws ServiceException, RemoteException { List<String> list = new ArrayList<>(); for (ProjectVersionData pvd : getVersions(projectID)) { if ((released && pvd.getReleased()) || ((!released) && (!pvd.getReleased()))) { list.add(pvd.getName()); } } Collections.sort(list); return StringUtils.toCustomFieldList(list); } private void initTags(boolean enforceUpdate) throws ServiceException, RemoteException { if (enforceUpdate) { tags = null; } if (tags == null) { tags = new HashMap<>(); MantisConnectPortType mcpt = mr.getClient(); BigInteger PAGE_SIZE = BigInteger.valueOf(1000); for (int i = 0; i < 1000; i++) { TagData[] tagList = mcpt.mc_tag_get_all( mr.getInfo().getUsername(), new String(mr.getInfo().getPassword()), BigInteger.valueOf(i), PAGE_SIZE).getResults(); for (TagData tag : tagList) { tags.put(tag.getId(), tag); } if (tagList.length < PAGE_SIZE.intValue()) { break; } } } } public TagData getTag(BigInteger id) throws ServiceException, RemoteException { initTags(false); return tags.get(id); } public List<TagData> getTags() throws ServiceException, RemoteException { initTags(false); return new ArrayList<>(tags.values()); } public TagData addTag(String tagName) throws ServiceException, RemoteException { for (TagData td : getTags()) { if (td.getName().equals(tagName)) { return td; } } TagData newTag = new TagData(); newTag.setDescription(""); newTag.setName(tagName); BigInteger id = mr.getClient().mc_tag_add( mr.getInfo().getUsername(), new String(mr.getInfo().getPassword()), newTag); newTag.setId(id); tags.put(id, newTag); return newTag; } }