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 result.put(getResourceType(BoxFileUploadSession.class), BoxFileUploadSession.class); 064 result.put(getResourceType(BoxWebLink.class), BoxWebLink.class); 065 066 return Collections.unmodifiableMap(result); 067 } 068 069 /** 070 * Resolves {@link BoxResourceType} for a provided {@link BoxResource} {@link Class}. 071 * 072 * @param clazz 073 * {@link BoxResource} type 074 * @return resolved {@link BoxResourceType#value()} 075 */ 076 public static String getResourceType(Class<? extends BoxResource> clazz) { 077 BoxResourceType resource = clazz.getAnnotation(BoxResourceType.class); 078 if (resource == null) { 079 throw new IllegalArgumentException("Provided BoxResource type does not have @BoxResourceType annotation."); 080 } 081 return resource.value(); 082 } 083 084 static BoxResource.Info parseInfo(BoxAPIConnection api, JsonObject jsonObject) { 085 String type = jsonObject.get("type").asString(); 086 String id = jsonObject.get("id").asString(); 087 088 try { 089 Class<? extends BoxResource> resourceClass = RESOURCE_CLASS_BY_TYPE.get(type); 090 Constructor<? extends BoxResource> resourceConstructor = 091 resourceClass.getConstructor(BoxAPIConnection.class, String.class); 092 093 Class<?> infoClass = resourceClass.getClassLoader().loadClass(resourceClass.getCanonicalName() + "$Info"); 094 Constructor<?> infoConstructor = infoClass.getDeclaredConstructor(resourceClass, JsonObject.class); 095 096 BoxResource resource = resourceConstructor.newInstance(api, id); 097 return (BoxResource.Info) infoConstructor.newInstance(resource, jsonObject); 098 099 } catch (ClassNotFoundException e) { 100 return null; 101 } catch (NoSuchMethodException e) { 102 return null; 103 } catch (IllegalAccessException e) { 104 throw new BoxAPIException("Can not create BoxResource.Info instance:", e); 105 } catch (InvocationTargetException e) { 106 throw new BoxAPIException("Can not create BoxResource.Info instance:", e); 107 } catch (InstantiationException e) { 108 throw new BoxAPIException("Can not create BoxResource.Info instance:", e); 109 } 110 } 111 112 /** 113 * Gets the API connection used by this resource. 114 * @return the API connection used by this resource. 115 */ 116 public BoxAPIConnection getAPI() { 117 return this.api; 118 } 119 120 /** 121 * Gets the ID of this resource. 122 * @return the ID of this resource. 123 */ 124 public String getID() { 125 return this.id; 126 } 127 128 /** 129 * Indicates whether this BoxResource is equal to another BoxResource. Two BoxResources are equal if they have the 130 * same type and ID. 131 * @param other the other BoxResource to compare. 132 * @return true if the type and IDs of the two resources are equal; otherwise false. 133 */ 134 @Override 135 public boolean equals(Object other) { 136 if (other == null) { 137 return false; 138 } 139 140 if (this.getClass().equals(other.getClass())) { 141 BoxResource otherResource = (BoxResource) other; 142 return this.getID().equals(otherResource.getID()); 143 } 144 145 return false; 146 } 147 148 /** 149 * Returns a hash code value for this BoxResource. 150 * @return a hash code value for this BoxResource. 151 */ 152 @Override 153 public int hashCode() { 154 return this.getID().hashCode(); 155 } 156 157 /** 158 * Contains information about a BoxResource. 159 */ 160 public abstract class Info extends BoxJSONObject { 161 /** 162 * Constructs an empty Info object. 163 */ 164 public Info() { 165 super(); 166 } 167 168 /** 169 * Constructs an Info object by parsing information from a JSON string. 170 * @param json the JSON string to parse. 171 */ 172 public Info(String json) { 173 super(json); 174 } 175 176 /** 177 * Constructs an Info object using an already parsed JSON object. 178 * @param jsonObject the parsed JSON object. 179 */ 180 Info(JsonObject jsonObject) { 181 super(jsonObject); 182 } 183 184 /** 185 * Gets the ID of the resource associated with this Info. 186 * @return the ID of the associated resource. 187 */ 188 public String getID() { 189 return BoxResource.this.getID(); 190 } 191 192 /** 193 * Gets the resource associated with this Info. 194 * @return the associated resource. 195 */ 196 public abstract BoxResource getResource(); 197 } 198}