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