All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.taskadapter.redmineapi.internal.RedmineJSONBuilder Maven / Gradle / Ivy

Go to download

Free open-source Java API for Redmine and Chiliproject bug/task management systems. This project was originally a part of Task Adapter application (http://www.taskadapter.com) and then was open-sourced.

The newest version!
package com.taskadapter.redmineapi.internal;

import com.taskadapter.redmineapi.RedmineInternalError;
import com.taskadapter.redmineapi.bean.Attachment;
import com.taskadapter.redmineapi.bean.CustomField;
import com.taskadapter.redmineapi.bean.Group;
import com.taskadapter.redmineapi.bean.Identifiable;
import com.taskadapter.redmineapi.bean.Issue;
import com.taskadapter.redmineapi.bean.IssueCategory;
import com.taskadapter.redmineapi.bean.IssueRelation;
import com.taskadapter.redmineapi.bean.Membership;
import com.taskadapter.redmineapi.bean.Project;
import com.taskadapter.redmineapi.bean.Property;
import com.taskadapter.redmineapi.bean.PropertyStorage;
import com.taskadapter.redmineapi.bean.Role;
import com.taskadapter.redmineapi.bean.TimeEntry;
import com.taskadapter.redmineapi.bean.Tracker;
import com.taskadapter.redmineapi.bean.User;
import com.taskadapter.redmineapi.bean.Version;
import com.taskadapter.redmineapi.bean.Watcher;
import com.taskadapter.redmineapi.bean.WikiPage;
import com.taskadapter.redmineapi.bean.WikiPageDetail;
import com.taskadapter.redmineapi.internal.json.JsonObjectWriter;
import com.taskadapter.redmineapi.internal.json.JsonOutput;
import org.json.JSONException;
import org.json.JSONWriter;

import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Converts Redmine objects to JSon format.
 */
public class RedmineJSONBuilder {

    /**
	 * Writes a "create project" request.
	 * 
	 * @param writer
	 *            project writer.
	 * @param project
	 *            project to create.
	 * @throws IllegalArgumentException
	 *             if some project fields are not configured.
	 * @throws JSONException
	 *             if IO error occurs.
	 */
	public static void writeProject(JSONWriter writer, Project project)
			throws IllegalArgumentException, JSONException {
		/* Validate project */
		if (project.getName() == null)
			throw new IllegalArgumentException(
					"Project name must be set to create a new project");
		if (project.getIdentifier() == null)
			throw new IllegalArgumentException(
					"Project identifier must be set to create a new project");

		writeProject(project, writer);
	}

	static void writeTimeEntry(JSONWriter writer, TimeEntry timeEntry)
			throws JSONException {
		PropertyStorage storage = timeEntry.getStorage();
		addIfSet(writer, "id", storage, TimeEntry.DATABASE_ID);
		addIfSet(writer, "project_id", storage, TimeEntry.PROJECT_ID);
		addIfSet(writer, "issue_id", storage, TimeEntry.ISSUE_ID);
		addIfSet(writer, "user_id", storage, TimeEntry.USER_ID);
		addIfSet(writer, "activity_id",storage, TimeEntry.ACTIVITY_ID);
		addIfSet(writer, "hours", storage, TimeEntry.HOURS);
		addIfSet(writer, "comments", storage, TimeEntry.COMMENT);
		addIfSetShort2(writer, "spent_on", storage, TimeEntry.SPENT_ON);
		addIfSetFullDate(writer, "created_on", storage, TimeEntry.SPENT_ON);
		addIfSetFullDate(writer, "updated_on", storage, TimeEntry.SPENT_ON);
		writeCustomFields(writer, timeEntry.getCustomFields());
	}

	static void writeRelation(JSONWriter writer, IssueRelation relation)
			throws JSONException {
		PropertyStorage storage = relation.getStorage();
		addIfSet(writer, "issue_to_id", storage, IssueRelation.ISSUE_TO_ID);
		addIfSet(writer, "relation_type", storage, IssueRelation.RELATION_TYPE);
		addIfSet(writer, "delay", storage, IssueRelation.DELAY);
	}

	static void writeVersion(JSONWriter writer, Version version)
			throws JSONException {
		PropertyStorage storage = version.getStorage();
		addIfSet(writer, "id", storage, Version.DATABASE_ID);
		addIfSet(writer, "project_id", storage, Version.PROJECT_ID);
		addIfSet(writer, "name", storage, Version.NAME);
		addIfSet(writer, "description", storage, Version.DESCRIPTION);
		addIfSet(writer, "sharing", storage, Version.SHARING);
		addIfSet(writer, "status", storage, Version.STATUS);
		addIfSetShort2(writer, "due_date", storage, Version.DUE_DATE);
		addIfSetFullDate(writer, "created_on", storage, Version.CREATED_ON);
		addIfSetFullDate(writer, "updated_on", storage, Version.UPDATED_ON);
		writeCustomFields(writer, version.getCustomFields());
	}

	/**
	 * Converts object to a "simple" json.
	 * 
	 * @param tag
	 *            object tag.
	 * @param object
	 *            object to convert.
	 * @param writer
	 *            object writer.
	 * @return object String representation.
	 * @throws RedmineInternalError
	 *             if conversion fails.
	 */
	public static  String toSimpleJSON(String tag, T object,
			JsonObjectWriter writer) throws RedmineInternalError {
		final StringWriter swriter = new StringWriter();
		final JSONWriter jsWriter = new JSONWriter(swriter);
		try {
			jsWriter.object();
			jsWriter.key(tag);
			jsWriter.object();
			writer.write(jsWriter, object);
			jsWriter.endObject();
			jsWriter.endObject();
		} catch (JSONException e) {
			throw new RedmineInternalError("Unexpected JSONException", e);
		}

		return swriter.toString();
	}

	public static void writeProject(Project project, final JSONWriter writer)
			throws JSONException {
		PropertyStorage storage = project.getStorage();
		addIfSet(writer, "id", storage, Project.DATABASE_ID);
		addIfSet(writer, "identifier", storage, Project.STRING_IDENTIFIER);
		addIfSet(writer, "name", storage, Project.NAME);
		addIfSet(writer, "description", storage, Project.DESCRIPTION);
		addIfSet(writer, "homepage", storage, Project.HOMEPAGE);
		addIfSetFullDate(writer, "created_on", storage, Project.CREATED_ON);
		addIfSetFullDate(writer, "updated_on", storage, Project.UPDATED_ON);
		writeCustomFields(writer, project.getCustomFields());
		addIfSet(writer, "parent_id", storage, Project.PARENT_DATABASE_ID);
		addIfSet(writer, "status", storage, Project.STATUS);
		addIfSet(writer, "is_public", storage, Project.PUBLIC);
		addIfSet(writer, "inherit_members", storage, Project.INHERIT_MEMBERS);
		writeProjectTrackers(writer, project);
	}
	private static void writeProjectTrackers(JSONWriter writer, Project project) throws JSONException {
		//skip if storage is not already set to allow new projects get the redmine system default trackers
		PropertyStorage storage = project.getStorage();
		if (storage.isPropertySet(Project.TRACKERS)) {
			Collection trackerIds=new ArrayList<>();
			for (Tracker tracker : project.getTrackers())
				trackerIds.add(tracker.getId());
			JsonOutput.addScalarArray(writer, "tracker_ids", trackerIds, RedmineJSONBuilder::writeScalarValue);			
		}
	}

	static void writeScalarValue(JSONWriter writer, Object object) throws JSONException {
		writer.value(object);
	}

	public static void writeCategory(final JSONWriter writer, IssueCategory category) throws JSONException {
		PropertyStorage storage = category.getStorage();
		writer.key("id");
		writer.value(category.getId());
		addIfSet(writer, "name", storage, IssueCategory.NAME);
		addIfSet(writer, "project_id", storage, IssueCategory.PROJECT_ID);
		addIfSet(writer, "assigned_to_id", storage, IssueCategory.ASSIGNEE_ID);
	}

	public static void writeUser(final JSONWriter writer, User user)
			throws JSONException {
		PropertyStorage storage = user.getStorage();
		addIfSet(writer, "id", storage, User.ID);
		addIfSet(writer, "login", storage, User.LOGIN);
		addIfSet(writer, "password", storage, User.PASSWORD);
		addIfSet(writer, "firstname", storage, User.FIRST_NAME);
		addIfSet(writer, "lastname", storage, User.LAST_NAME);
		// TODO I don't think this "name" is required... check this.
//		addIfSet(writer, "name", storage, User.FULL_NAME);
		addIfSet(writer, "mail", storage, User.MAIL);
		addIfSet(writer, "auth_source_id", storage, User.AUTH_SOURCE_ID);
		addIfSet(writer, "status", storage, User.STATUS);
		addIfSetFullDate(writer, "created_on", storage, User.CREATED_ON);
		addIfSetFullDate(writer, "last_login_on", storage, User.LAST_LOGIN_ON);
		addIfSet(writer, "mail_notification", storage, User.MAIL_NOTIFICATION);
		addIfSet(writer, "must_change_passwd", storage, User.MUST_CHANGE_PASSWD);
		addIfSet(writer, "generate_password", storage, User.GENERATE_PASSWORD);
		writeCustomFields(writer, user.getCustomFields());

	}

    public static void writeGroup(final JSONWriter writer, Group group) throws JSONException {
		PropertyStorage storage = group.getStorage();
		addIfSet(writer, "id", storage, Group.ID);
		addIfSet(writer, "name", storage, Group.NAME);
	}

	public static void writeIssue(final JSONWriter writer, Issue issue) throws JSONException {
        PropertyStorage storage = issue.getStorage();
		addIfSet(writer, "id", storage, Issue.DATABASE_ID);
		addIfSet(writer, "subject", storage, Issue.SUBJECT);
		addIfSet(writer, "parent_issue_id", storage, Issue.PARENT_ID);
		addIfSet(writer, "estimated_hours", storage, Issue.ESTIMATED_HOURS);
		addIfSet(writer, "spent_hours", storage, Issue.SPENT_HOURS);
		addIfSet(writer, "assigned_to_id", storage, Issue.ASSIGNEE_ID);
		addIfSet(writer, "priority_id", storage, Issue.PRIORITY_ID);
                addIfSet(writer, "done_ratio", storage, Issue.DONE_RATIO);
		addIfSet(writer, "is_private", storage, Issue.PRIVATE_ISSUE);
		addIfSet(writer, "project_id", storage, Issue.PROJECT_ID);
		addIfSet(writer, "author_id", storage, Issue.AUTHOR_ID);
		addIfSet(writer, "start_date", storage, Issue.START_DATE, RedmineDateParser.SHORT_DATE_FORMAT_V2.get());
		addIfSet(writer, "due_date", storage, Issue.DUE_DATE, RedmineDateParser.SHORT_DATE_FORMAT_V2.get());
                addIfSetIdentifiable(writer, "tracker_id", storage, Issue.TRACKER);
		addIfSet(writer, "description", storage, Issue.DESCRIPTION);

		addIfSetFullDate(writer, "created_on", storage, Issue.CREATED_ON);
		addIfSetFullDate(writer, "updated_on", storage, Issue.UPDATED_ON);
		addIfSet(writer, "status_id", storage, Issue.STATUS_ID);
                addIfSetIdentifiable(writer, "fixed_version_id", storage, Issue.TARGET_VERSION);
                addIfSetIdentifiable(writer, "category_id", storage, Issue.ISSUE_CATEGORY);
                addIfSet(writer, "notes", storage, Issue.NOTES);
		addIfSet(writer, "private_notes", storage, Issue.PRIVATE_NOTES);
		writeCustomFields(writer, issue.getCustomFields());

        Collection issueWatchers = issue.getWatchers();
        if (issueWatchers != null && !issueWatchers.isEmpty()) {
            writeWatchers(writer, issueWatchers);
        }

        final List uploads = issue.getAttachments()
				.stream()
				.filter(attachment -> attachment.getToken() != null)
				.collect(Collectors.toList());

		JsonOutput.addArrayIfNotEmpty(writer, "uploads", uploads, RedmineJSONBuilder::writeUpload);

		/*
		 * Journals and Relations cannot be set for an issue during creation or
		 * updates.
		 */
	}

	private static void addIfSet(JSONWriter writer, String jsonKeyName, PropertyStorage storage, Property property) throws JSONException {
		if (storage.isPropertySet(property)) {
			writer.key(jsonKeyName);
			writer.value(storage.get(property));
		}
	}

	public static void addIfSetShort2(JSONWriter writer, String jsonKeyName, PropertyStorage storage, Property property) throws JSONException {
		final SimpleDateFormat format = RedmineDateParser.SHORT_DATE_FORMAT_V2.get();
		addIfSet(writer, jsonKeyName, storage, property, format);
	}

	private static void addIfSetFullDate(JSONWriter writer, String jsonKeyName, PropertyStorage storage, Property property) throws JSONException {
		final SimpleDateFormat format = RedmineDateParser.FULL_DATE_FORMAT.get();
		addIfSet(writer, jsonKeyName, storage, property, format);
	}
        
        private static void addIfSetIdentifiable(JSONWriter writer, String jsonKeyName, PropertyStorage storage, Property property) throws JSONException {
                if (storage.isPropertySet(property)) {
                        final Identifiable propertyValue = storage.get(property);
                        writer.key(jsonKeyName);
                        if(propertyValue != null) {
                            writer.value(propertyValue.getId());
                        } else {
                            writer.value(null);
                        }
                } 
        }

	private static void addIfSet(JSONWriter writer, String jsonKeyName, PropertyStorage storage, Property property, SimpleDateFormat format) throws JSONException {
		if (storage.isPropertySet(property)) {
			JsonOutput.add(writer, jsonKeyName, storage.get(property), format);
		}
	}

	public static void writeUpload(JSONWriter writer, Attachment attachment) throws JSONException {
		PropertyStorage storage = attachment.getStorage();
		addIfSet(writer, "token", storage, Attachment.TOKEN);
		addIfSet(writer, "filename", storage, Attachment.FILE_NAME);
		addIfSet(writer, "content_type", storage, Attachment.CONTENT_TYPE);
		addIfSet(writer, "description", storage, Attachment.DESCRIPTION);
	}

	public static void writeMembership(JSONWriter writer, Membership membership)
			throws JSONException {
		final PropertyStorage storage = membership.getStorage();
		addIfSet(writer, "user_id", storage, Membership.USER_ID);
		addIfSet(writer, "group_id", storage, Membership.GROUP_ID);
		if (membership.getRoles() != null) {
			writer.key("role_ids");
			writer.array();
			for (Role role : membership.getRoles()) {
				writer.value(role.getId().longValue());
			}
			writer.endArray();
		}
	}

	private static void writeCustomFields(JSONWriter writer, Collection customFields) throws JSONException {
		if (customFields == null || customFields.isEmpty()) {
            return;
        }
		writer.key("custom_field_values").object();
		for (CustomField field : customFields) {
            // see https://github.com/taskadapter/redmine-java-api/issues/54
            Object valueToWrite;
            if (field.isMultiple()) {
                valueToWrite = field.getValues();
            } else {
			    valueToWrite = field.getValue();
            }
            writer.key(Integer.toString(field.getId())).value(valueToWrite);
		}
		writer.endObject();
	}

	public static void writeWatchers(JSONWriter writer, Collection watchers)
			throws JSONException {
            if (watchers == null || watchers.isEmpty()) {
                return;
            }

            writer.key("watcher_user_ids");
            writer.array();
            for (Watcher watcher : watchers) {
                if (watcher.getId() != null) {
                    writer.value(watcher.getId().longValue());
                }
            }
            writer.endArray();
	}

	public static void writeWikiPageDetail(JSONWriter writer, WikiPageDetail detail) throws JSONException {
		PropertyStorage storage = detail.getStorage();
		addIfSet(writer, "text", storage, WikiPageDetail.TEXT);
		addIfSet(writer, "comments", storage, WikiPageDetail.COMMENTS);
		addIfSet(writer, "version", storage, WikiPage.VERSION);
		JsonOutput.addArrayIfNotEmpty(writer, "uploads", detail.getAttachments(), RedmineJSONBuilder::writeUpload);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy