001package com.box.sdk; 002 003import java.lang.reflect.Constructor; 004import java.lang.reflect.InvocationTargetException; 005import java.util.Collections; 006import java.util.Map; 007import java.util.concurrent.ConcurrentHashMap; 008 009import com.eclipsesource.json.JsonObject; 010 011/** 012 * The abstract base class for all resource types (files, folders, comments, collaborations, etc.) used by the API. 013 * 014 * <p>Every API resource has an ID and a {@link BoxAPIConnection} that it uses to communicate with the API. Some 015 * resources also have an associated {@link Info} class that contains information about the resource.</p> 016 */ 017public abstract class BoxResource { 018 019 /** 020 * @see #initResourceClassByType() 021 */ 022 private static final Map<String, Class<? extends BoxResource>> RESOURCE_CLASS_BY_TYPE = initResourceClassByType(); 023 024 private final BoxAPIConnection api; 025 private final String id; 026 027 /** 028 * Constructs a BoxResource for a resource with a given ID. 029 * 030 * @param api the API connection to be used by the resource. 031 * @param id the ID of the resource. 032 */ 033 public BoxResource(BoxAPIConnection api, String id) { 034 this.api = api; 035 this.id = id; 036 } 037 038 /** 039 * @return Builds {@link Map} between String {@link #getResourceType(Class)} and {@link BoxResource} type. 040 */ 041 private static Map<String, Class<? extends BoxResource>> initResourceClassByType() { 042 Map<String, Class<? extends BoxResource>> result = 043 new ConcurrentHashMap<String, Class<? extends BoxResource>>(); 044 result.put(getResourceType(BoxFolder.class), BoxFolder.class); 045 result.put(getResourceType(BoxFile.class), BoxFile.class); 046 result.put(getResourceType(BoxComment.class), BoxComment.class); 047 result.put(getResourceType(BoxCollaboration.class), BoxCollaboration.class); 048 result.put(getResourceType(BoxTask.class), BoxTask.class); 049 result.put(getResourceType(BoxTaskAssignment.class), BoxTaskAssignment.class); 050 result.put(getResourceType(BoxUser.class), BoxUser.class); 051 result.put(getResourceType(BoxGroup.class), BoxGroup.class); 052 result.put(getResourceType(BoxGroupMembership.class), BoxGroupMembership.class); 053 result.put(getResourceType(BoxEvent.class), BoxEvent.class); 054 result.put(getResourceType(BoxWebHook.class), BoxWebHook.class); 055 result.put(getResourceType(BoxCollection.class), BoxCollection.class); 056 result.put(getResourceType(BoxDevicePin.class), BoxDevicePin.class); 057 result.put(getResourceType(BoxRetentionPolicy.class), BoxRetentionPolicy.class); 058 result.put(getResourceType(BoxRetentionPolicyAssignment.class), BoxRetentionPolicyAssignment.class); 059 result.put(getResourceType(BoxFileVersionRetention.class), BoxFileVersionRetention.class); 060 result.put(getResourceType(BoxLegalHoldPolicy.class), BoxLegalHoldPolicy.class); 061 result.put(getResourceType(BoxLegalHoldAssignment.class), BoxLegalHoldAssignment.class); 062 result.put(getResourceType(BoxFileVersionLegalHold.class), BoxFileVersionLegalHold.class); 063 return Collections.unmodifiableMap(result); 064 } 065 066 /** 067 * Resolves {@link BoxResourceType} for a provided {@link BoxResource} {@link Class}. 068 * 069 * @param clazz 070 * {@link BoxResource} type 071 * @return resolved {@link BoxResourceType#value()} 072 */ 073 public static String getResourceType(Class<? extends BoxResource> clazz) { 074 BoxResourceType resource = clazz.getAnnotation(BoxResourceType.class); 075 if (resource == null) { 076 throw new IllegalArgumentException("Provided BoxResource type does not have @BoxResourceType annotation."); 077 } 078 return resource.value(); 079 } 080 081 static BoxResource.Info parseInfo(BoxAPIConnection api, JsonObject jsonObject) { 082 String type = jsonObject.get("type").asString(); 083 String id = jsonObject.get("id").asString(); 084 085 try { 086 Class<? extends BoxResource> resourceClass = RESOURCE_CLASS_BY_TYPE.get(type); 087 Constructor<? extends BoxResource> resourceConstructor = 088 resourceClass.getConstructor(BoxAPIConnection.class, String.class); 089 090 Class<?> infoClass = resourceClass.getClassLoader().loadClass(resourceClass.getCanonicalName() + "$Info"); 091 Constructor<?> infoConstructor = infoClass.getDeclaredConstructor(resourceClass, JsonObject.class); 092 093 BoxResource resource = resourceConstructor.newInstance(api, id); 094 return (BoxResource.Info) infoConstructor.newInstance(resource, jsonObject); 095 096 } catch (ClassNotFoundException e) { 097 return null; 098 } catch (NoSuchMethodException e) { 099 return null; 100 } catch (IllegalAccessException e) { 101 throw new BoxAPIException("Can not create BoxResource.Info instance:", e); 102 } catch (InvocationTargetException e) { 103 throw new BoxAPIException("Can not create BoxResource.Info instance:", e); 104 } catch (InstantiationException e) { 105 throw new BoxAPIException("Can not create BoxResource.Info instance:", e); 106 } 107 } 108 109 /** 110 * Gets the API connection used by this resource. 111 * @return the API connection used by this resource. 112 */ 113 public BoxAPIConnection getAPI() { 114 return this.api; 115 } 116 117 /** 118 * Gets the ID of this resource. 119 * @return the ID of this resource. 120 */ 121 public String getID() { 122 return this.id; 123 } 124 125 /** 126 * Indicates whether this BoxResource is equal to another BoxResource. Two BoxResources are equal if they have the 127 * same type and ID. 128 * @param other the other BoxResource to compare. 129 * @return true if the type and IDs of the two resources are equal; otherwise false. 130 */ 131 @Override 132 public boolean equals(Object other) { 133 if (other == null) { 134 return false; 135 } 136 137 if (this.getClass().equals(other.getClass())) { 138 BoxResource otherResource = (BoxResource) other; 139 return this.getID().equals(otherResource.getID()); 140 } 141 142 return false; 143 } 144 145 /** 146 * Returns a hash code value for this BoxResource. 147 * @return a hash code value for this BoxResource. 148 */ 149 @Override 150 public int hashCode() { 151 return this.getID().hashCode(); 152 } 153 154 /** 155 * Contains information about a BoxResource. 156 */ 157 public abstract class Info extends BoxJSONObject { 158 /** 159 * Constructs an empty Info object. 160 */ 161 public Info() { 162 super(); 163 } 164 165 /** 166 * Constructs an Info object by parsing information from a JSON string. 167 * @param json the JSON string to parse. 168 */ 169 public Info(String json) { 170 super(json); 171 } 172 173 /** 174 * Constructs an Info object using an already parsed JSON object. 175 * @param jsonObject the parsed JSON object. 176 */ 177 Info(JsonObject jsonObject) { 178 super(jsonObject); 179 } 180 181 /** 182 * Gets the ID of the resource associated with this Info. 183 * @return the ID of the associated resource. 184 */ 185 public String getID() { 186 return BoxResource.this.getID(); 187 } 188 189 /** 190 * Gets the resource associated with this Info. 191 * @return the associated resource. 192 */ 193 public abstract BoxResource getResource(); 194 } 195}