public class BintrayCallException extends HttpResponseException {

    private int statusCode;
    private String reason;
    private String message;

    public BintrayCallException(int statusCode, String reason, String message) {
        super(statusCode, reason);
        this.statusCode = statusCode;
        this.reason = reason;
        this.message = message;
    }

    public BintrayCallException(HttpResponse response) {
        super(response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase());
        String message = " ";
        String entity = null;
        int statusCode = response.getStatusLine().getStatusCode();
        if (response.getEntity() != null && statusCode != 405 && statusCode != 500) {
            try {
                entity = IOUtils.toString(response.getEntity().getContent());
                ObjectMapper mapper = ObjectMapperHelper.get();
                JsonNode node = mapper.readTree(entity);
                message = node.get("message").getTextValue();
            } catch (IOException | NullPointerException e) {
                //Null entity?
                if (entity != null) {
                    message = entity;
                }
            }
        }
        this.statusCode = statusCode;
        this.reason = response.getStatusLine().getReasonPhrase();
        this.message = message;
    }

    public BintrayCallException(Exception e) {
        super(HttpStatus.SC_BAD_REQUEST, e.getMessage());
        this.statusCode = HttpStatus.SC_BAD_REQUEST;
        this.reason = e.getMessage();
        this.message = (e.getCause() == null) ? " " : " : " + e.getCause().getMessage();
    }

    public int getStatusCode() {
        return statusCode;
    }

    public String getReason() {
        return reason;
    }

    @Override
    public String getMessage() {
        return message;
    }

    public void setMessage(String newMessage) {
        this.message = newMessage;
    }

    @Override
    public String toString() {
        return statusCode + ", " + reason + " " + message;
    }

} public class MultipleBintrayCallException extends Exception {

    List<BintrayCallException> exceptions;

    public MultipleBintrayCallException() {
        super();
        exceptions = new ArrayList<>();
    }

    public MultipleBintrayCallException(List<BintrayCallException> exceptions) {
        super();
        this.exceptions = exceptions;
    }

    public List<BintrayCallException> getExceptions() {
        return exceptions;
    }


} public class ObjectMapperHelper {

    public static ObjectMapper get() {
        return buildDetailsMapper();
    }

    private static ObjectMapper buildDetailsMapper() {
        ObjectMapper mapper = new ObjectMapper(new JsonFactory());

        // TODO: when moving to Jackson 2.x these can be replaced with JodaModule
        mapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);
        mapper.configure(SerializationConfig.Feature.WRITE_DATE_KEYS_AS_TIMESTAMPS, false);

        //Don't include keys with null values implicitly, only explicitly set values should be sent over
        mapper.configure(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY, false);
        mapper.configure(SerializationConfig.Feature.WRITE_NULL_MAP_VALUES, false);
        mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
        return mapper;
    }
} @JsonPropertyOrder({"name", "values", "type"})
@JsonIgnoreProperties(ignoreUnknown = true)
public class Attribute<T> {
    private static final Logger log = LoggerFactory.getLogger(Attribute.class);
    @JsonProperty("name")
    private String name;
    @JsonProperty("values")
    private List<T> values;
    @JsonProperty("type")
    private Type type;

    @SafeVarargs
    public Attribute(String name, T... values) {
        this(name, null, asList(values));
    }


    @SafeVarargs
    public Attribute(String name, Type type, T... values) {
        this(name, type, asList(values));
    }

    @JsonCreator
    public Attribute(@JsonProperty("name") String name, @JsonProperty("type") Type type, @JsonProperty("values") List<T> values) {
        this.name = name;
        if (type == null) {
            type = Type.string;     //Type defaults to string
        }
        this.type = type;
        this.values = values;
    }

    public static ObjectMapper getObjectMapper() {
        return ObjectMapperHelper.get();
    }

    /**
     * Produces a json from a list of attributes
     *
     * @param attributeDetails List of attributes to serialize
     * @return A string representing the json
     * @throws IOException
     */
    @JsonIgnore
    public static String getJsonFromAttributeList(List<Attribute> attributeDetails) throws IOException {
        ObjectMapper mapper = ObjectMapperHelper.get();
        String jsonContent;
        try {
            jsonContent = mapper.writeValueAsString(attributeDetails);
        } catch (IOException e) {
            log.error("Can't process the json file: " + e.getMessage());
            throw e;
        }
        return jsonContent;
    }

    @JsonIgnore
    public static List<Attribute> getAttributeListFromJson(InputStream inputStream) throws IOException {
        ObjectMapper mapper = ObjectMapperHelper.get();
        List<Attribute> attributes;
        try {
            attributes = mapper.readValue(inputStream, new TypeReference<List<Attribute>>() {
            });
        } catch (IOException e) {
            log.error("Can't process the json file: " + e.getMessage());
            throw e;
        }
        return attributes;
    }

    public String getName() {
        return name;
    }

    public List<T> getValues() {
        return values;
    }

    public Type getType() {
        return type;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Attribute attribute = (Attribute) o;

        if (!name.equals(attribute.name)) return false;
        if (!values.equals(attribute.values)) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = name.hashCode();
        result = 31 * result + type.hashCode();
        result = 31 * result + values.hashCode();
        return result;
    }

    @Override
    public String toString() {
        return "{" +
                "Name='" + name + '\'' +
                ", Type=" + type +
                ", Values=" + values +
                '}';
    }

    public enum Type {
        string, date, number, Boolean
    }
} @JsonIgnoreProperties(ignoreUnknown = true)
public class VersionDetails {

    //Properties marked with @JsonPropery here are serialized to the create \ update version requests, the rest are
    // only deserialized when getting the version info
    @JsonProperty("name")
    String name;
    @JsonProperty("desc")
    String description;
    @JsonIgnore
    String pkg;
    @JsonIgnore
    String repo;
    @JsonIgnore
    String owner;
    @JsonIgnore
    List<String> labels;
    @JsonIgnore
    List<String> attributeNames;
    @JsonIgnore
    DateTime created;
    @JsonIgnore
    DateTime updated;
    @JsonProperty("released")
    DateTime released;
    @JsonIgnore
    Integer ordinal;
    @JsonIgnore
    List<Attribute> attributes;
    @JsonIgnore
    boolean gpgSign;
    @JsonProperty(value = "github_release_notes_file")
    private String releaseNotesFile;
    @JsonProperty(value = "github_use_tag_release_notes")
    private Boolean useTagReleaseNotes;
    @JsonProperty("vcs_tag")
    private String vcsTag;

    //All other props that don't have specific fields
    private Map<String, Object> other = new HashMap<>();

    @JsonAnySetter
    public void set(String name, Object value) {
        other.put(name, value);
    }

    @JsonAnyGetter
    public Map<String, Object> other() {
        return other;
    }

    public VersionDetails() {

    }

    public VersionDetails(String name) {
        this.name = name;
    }

    public static ObjectMapper getObjectMapper() {
        return ObjectMapperHelper.get();
    }

    public VersionDetails description(String description) {
        this.description = description;
        return this;
    }

    public VersionDetails released(DateTime released) {
        this.released = released;
        return this;
    }

    public VersionDetails releaseNotesFile(String releaseNotesFile) {
        this.releaseNotesFile = releaseNotesFile;
        return this;
    }

    public VersionDetails useTagReleaseNotes(Boolean useTagReleaseNotes) {
        this.useTagReleaseNotes = useTagReleaseNotes;
        return this;
    }

    public VersionDetails vcsTag(String vcsTag) {
        this.vcsTag = vcsTag;
        return this;
    }

    public VersionDetails gpgSign(boolean gpgSign) {
        this.gpgSign = gpgSign;
        return this;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @JsonIgnore
    public String getPkg() {
        return pkg;
    }

    @JsonProperty("package")
    public void setPkg(String pkg) {
        this.pkg = pkg;
    }

    @JsonIgnore
    public String getRepo() {
        return repo;
    }

    @JsonProperty("repo")
    public void setRepo(String repo) {
        this.repo = repo;
    }

    @JsonIgnore
    public String getOwner() {
        return owner;
    }

    @JsonProperty("owner")
    public void setOwner(String owner) {
        this.owner = owner;
    }

    @JsonIgnore
    public List<String> getLabels() {
        return labels;
    }

    @JsonProperty("labels")
    public void setLabels(List<String> labels) {
        this.labels = labels;
    }

    @JsonIgnore
    public List<String> getAttributeNames() {
        return attributeNames;
    }

    @JsonProperty("attribute_names")
    public void setAttributeNames(List<String> attributeNames) {
        this.attributeNames = attributeNames;
    }

    @JsonIgnore
    public DateTime getCreated() {
        return created;
    }

    @JsonProperty("created")
    public void setCreated(DateTime created) {
        this.created = created;
    }

    @JsonIgnore
    public DateTime getUpdated() {
        return updated;
    }

    @JsonProperty("updated")
    public void setUpdated(DateTime updated) {
        this.updated = updated;
    }

    public DateTime getReleased() {
        return released;
    }

    public void setReleased(DateTime released) {
        this.released = released;
    }

    @JsonIgnore
    public Integer getOrdinal() {
        return ordinal;
    }

    @JsonProperty("ordinal")
    public void setOrdinal(Integer ordinal) {
        this.ordinal = ordinal;
    }

    public String getReleaseNotesFile() {
        return releaseNotesFile;
    }

    public void setReleaseNotesFile(String releaseNotesFile) {
        this.releaseNotesFile = releaseNotesFile;
    }

    public Boolean getUseTagReleaseNotes() {
        return useTagReleaseNotes;
    }

    public void setUseTagReleaseNotes(Boolean useTagReleaseNotes) {
        this.useTagReleaseNotes = useTagReleaseNotes;
    }

    public String getVcsTag() {
        return vcsTag;
    }

    public void setVcsTag(String vcsTag) {
        this.vcsTag = vcsTag;
    }

    @JsonIgnore
    public List<Attribute> getAttributes() {
        return attributes;
    }

    @JsonProperty("attributes")
    public void setAttributes(List<Attribute> attributes) {
        this.attributes = attributes;
    }

    @JsonIgnore
    public boolean isGpgSign() {
        return gpgSign;
    }

    @JsonProperty("gpgSign")
    public void setGpgSign(boolean gpgSign) {
        this.gpgSign = gpgSign;
    }
} public interface PackageHandle extends Handle<Pkg> {

    RepositoryHandle repository();

    VersionHandle version(String versionName);

    Pkg get() throws IOException, BintrayCallException;

    PackageHandle update(PackageDetails packageDetails) throws IOException, BintrayCallException;

    PackageHandle delete() throws BintrayCallException;

    boolean exists() throws BintrayCallException;

    VersionHandle createVersion(VersionDetails versionDetails) throws IOException, BintrayCallException;

    PackageHandle setAttributes(PackageDetails packageDetails) throws IOException, BintrayCallException;

    PackageHandle setAttributes(List<Attribute> attributes) throws IOException, BintrayCallException;

    PackageHandle updateAttributes(PackageDetails packageDetails) throws IOException, BintrayCallException;

    PackageHandle updateAttributes(List<Attribute> attributes) throws IOException, BintrayCallException;

    String name();

    String getCurrentPackageUri();
} public interface VersionHandle extends Handle<Version> {

    PackageHandle pkg();

    Version get() throws IOException, BintrayCallException;

    VersionHandle update(VersionDetails versionDetails) throws IOException, BintrayCallException;

    VersionHandle delete() throws BintrayCallException;

    boolean exists() throws BintrayCallException;

    VersionHandle setAttributes(VersionDetails versionDetails) throws IOException, BintrayCallException;

    VersionHandle setAttributes(List<Attribute> attributes) throws IOException, BintrayCallException;

    VersionHandle updateAttributes(VersionDetails versionDetails) throws IOException, BintrayCallException;

    VersionHandle updateAttributes(List<Attribute> attributes) throws IOException, BintrayCallException;

    VersionHandle upload(Map<String, InputStream> content) throws MultipleBintrayCallException;

    VersionHandle upload(Map<String, InputStream> content, boolean overrideExisting) throws MultipleBintrayCallException;

    VersionHandle upload(String path, InputStream content) throws BintrayCallException;

    VersionHandle upload(String path, InputStream content, boolean overrideExisting) throws BintrayCallException;

    VersionHandle uploadVagrant(String path, String boxProvider, InputStream content) throws BintrayCallException;

    VersionHandle uploadVagrant(String path, String boxProvider, InputStream content, boolean overrideExisting) throws BintrayCallException;

    VersionHandle uploadDebian(String path, String distribution, String component, String architecture,
            InputStream content) throws BintrayCallException;

    VersionHandle uploadDebian(String path, String distribution, String component, String architecture,
            InputStream content, boolean overrideExisting) throws BintrayCallException;

    VersionHandle uploadDebian(String path, List<String> distributions, List<String> components,
            List<String> architectures, InputStream content) throws BintrayCallException;

    VersionHandle uploadDebian(String path, List<String> distributions, List<String> components,
            List<String> architectures, InputStream content, boolean overrideExisting) throws BintrayCallException;

    VersionHandle publish() throws BintrayCallException;

    VersionHandle publish(String gpgPassphrase) throws BintrayCallException;

    VersionHandle publishSync() throws BintrayCallException;

    VersionHandle discard() throws BintrayCallException;

    VersionHandle sign(String passphrase, int fileCount) throws BintrayCallException;

    VersionHandle sign(int fileCount) throws BintrayCallException;

    String getVersionUri();
} public interface Version {

    String name();

    String description();

    String pkg();

    String repository();

    String owner();

    List<String> labels();

    List<String> attributeNames();

    DateTime created();

    DateTime updated();

    DateTime released();

    Integer ordinal();

    String vcsTag();

    Object getFieldByKey(String key);
} public class VersionImpl implements Version {
    private static final Logger log = LoggerFactory.getLogger(VersionImpl.class);

    private String name;
    private String description;
    private String pkg;
    private String repository;
    private String owner;
    private List<String> labels;
    private List<String> attributeNames;
    private DateTime created;
    private DateTime updated;
    private DateTime released;
    private Integer ordinal;
    private String vcsTag;
    private Map<String, Object> other;

    public VersionImpl() {
    }

    public VersionImpl(VersionDetails versionDetails) {
        this.name = versionDetails.getName();
        this.description = versionDetails.getDescription();
        this.pkg = versionDetails.getPkg();
        this.repository = versionDetails.getRepo();
        this.owner = versionDetails.getOwner();
        this.labels = versionDetails.getLabels();
        this.attributeNames = versionDetails.getAttributeNames();
        this.created = versionDetails.getCreated();
        this.updated = versionDetails.getUpdated();
        this.released = versionDetails.getReleased();
        this.ordinal = versionDetails.getOrdinal();
        this.vcsTag = versionDetails.getVcsTag();
        this.other = versionDetails.other();
    }

    public VersionImpl(String name, String description, String pkg, String repository, String owner, List<String> labels,
            List<String> attributeNames, DateTime created, DateTime updated, DateTime released, int ordinal, String vcsTag) {
        this.name = name;
        this.description = description;
        this.pkg = pkg;
        this.repository = repository;
        this.owner = owner;
        this.labels = labels;
        this.attributeNames = attributeNames;
        this.created = created;
        this.updated = updated;
        this.released = released;
        this.ordinal = ordinal;
        this.vcsTag = vcsTag;
    }

    public static String getCreateUpdateJson(VersionDetails versionDetails) throws IOException {
        ObjectMapper mapper = ObjectMapperHelper.get();
        String jsonContent;
        try {
            jsonContent = mapper.writeValueAsString(versionDetails);
        } catch (IOException e) {
            log.error("Can't process the json file: " + e.getMessage());
            log.debug("{}", e);
            throw e;
        }
        return jsonContent;
    }

    @Override
    public String name() {
        return name;
    }

    @Override
    public String description() {
        return description;
    }

    @Override
    public String pkg() {
        return pkg;
    }

    @Override
    public String repository() {
        return repository;
    }

    @Override
    public String owner() {
        return owner;
    }

    @Override
    public List<String> labels() {
        return labels;
    }

    @Override
    public List<String> attributeNames() {
        return attributeNames;
    }

    @Override
    public DateTime created() {
        return created;
    }

    @Override
    public DateTime updated() {
        return updated;
    }

    @Override
    public DateTime released() {
        return released;
    }

    @Override
    public Integer ordinal() {
        return ordinal;
    }

    @Override
    public String vcsTag() {
        return vcsTag;
    }

    public Object getFieldByKey(String key) {
        return other.get(key);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        VersionImpl version = (VersionImpl) o;

        if (!name.equals(version.name)) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return name.hashCode();
    }

    @Override
    public String toString() {
        return "Version{" +
                "getName='" + name + '\'' +
                ", description='" + description + '\'' +
                ", pkg='" + pkg + '\'' +
                ", repository='" + repository + '\'' +
                ", owner='" + owner + '\'' +
                ", labels=" + labels +
                ", attributeNames=" + attributeNames +
                ", created=" + created +
                ", updated=" + updated +
                ", released=" + released +
                ", ordinal=" + ordinal +
                '}';
    }
} public interface BintrayClientConstatnts {

    String API_USERS = "users/";
    String API_REPOS = "repos/";
    String API_PKGS = "packages/";
    String API_VER = "versions/";
    String API_GPG = "gpg/";
    String API_CONTENT = "content/";
    String API_PRODUCTS = "products/";

    String API_PUBLISH = "/publish";
    String API_ATTR = "/attributes";

    String GPG_SIGN_HEADER = "X-GPG-PASSPHRASE";
}
import com.jfrog.bintray.client.api.BintrayCallException;
import com.jfrog.bintray.client.api.MultipleBintrayCallException;
import com.jfrog.bintray.client.api.ObjectMapperHelper;
import com.jfrog.bintray.client.api.details.Attribute;
import com.jfrog.bintray.client.api.details.VersionDetails;
import com.jfrog.bintray.client.api.handle.PackageHandle;
import com.jfrog.bintray.client.api.handle.VersionHandle;
import com.jfrog.bintray.client.api.model.Version;
import com.jfrog.bintray.client.impl.model.VersionImpl;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.jfrog.bintray.client.api.BintrayClientConstatnts.*;
package com.jfrog.bintray.client.impl.handle;




/**
 * @author Dan Feldman
 */
class VersionHandleImpl implements VersionHandle {
    private static final Logger log = LoggerFactory.getLogger(VersionHandleImpl.class);

    private static final String OVERRIDE_HEADER = "X-Bintray-Override";
    private static final String DEB_DIST_HEADER = "X-Bintray-Debian-Distribution";
    private static final String DEB_COMP_HEADER = "X-Bintray-Debian-Component";
    private static final String DEB_ARCH_HEADER = "X-Bintray-Debian-Architecture";

    private BintrayImpl bintrayHandle;
    private String name;
    private PackageHandle packageHandle;