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