001 package edu.nrao.sss.model.resource; 002 003 import java.io.FileNotFoundException; 004 import java.io.Reader; 005 import java.io.Writer; 006 import java.util.ArrayList; 007 import java.util.Date; 008 import java.util.HashMap; 009 import java.util.List; 010 011 import javax.xml.bind.JAXBException; 012 import javax.xml.bind.annotation.XmlElement; 013 import javax.xml.bind.annotation.XmlElementRef; 014 import javax.xml.bind.annotation.XmlElementWrapper; 015 import javax.xml.bind.annotation.XmlRootElement; 016 import javax.xml.bind.annotation.XmlType; 017 import javax.xml.stream.XMLStreamException; 018 019 import edu.nrao.sss.catalog.Catalog; 020 import edu.nrao.sss.model.RepositoryException; 021 import edu.nrao.sss.model.UserAccountable; 022 import edu.nrao.sss.util.Identifiable; 023 import edu.nrao.sss.util.JaxbUtility; 024 import edu.nrao.sss.util.StringUtil; 025 026 /** 027 * A catalog of {@link Resource}s. 028 * <p> 029 * Each entry in a resource catalog is a {@code Resource}. 030 * This catalog also supports 031 * the notion of {@link ResourceGroup}s, which serve to 032 * associate resources with similar traits with one another.</p> 033 * <p> 034 * <b>Version Info:</b> 035 * <table style="margin-left:2em"> 036 * <tr><td>$Revision: 1709 $</td></tr> 037 * <tr><td>$Date: 2008-11-14 11:22:37 -0700 (Fri, 14 Nov 2008) $</td></tr> 038 * <tr><td>$Author: dharland $ (last person to modify)</td></tr> 039 * </table></p> 040 * 041 * @author David M. Harland 042 * @since 2006-10-20 043 */ 044 @XmlRootElement 045 @XmlType(propOrder= {"owner", 046 "createdBy","createdOn","lastUpdatedBy","lastUpdatedOn", 047 "entries", "resourceGroups" 048 }) 049 public class ResourceCatalog 050 extends Catalog<Resource, ResourceGroup, ResourceCatalog> 051 implements Identifiable, UserAccountable, ResourceProvider 052 { 053 //USER TRACKING 054 private Long owner; //This is a user ID 055 private Long createdBy; //This is a user ID 056 private Date createdOn; 057 private Long lastUpdatedBy; //This is a user ID 058 private Date lastUpdatedOn; 059 060 /** Creates a new catalog with a default name. */ 061 public ResourceCatalog() 062 { 063 this(null); 064 } 065 066 /** 067 * Creates a new catalog with the given name. 068 * 069 * @param nameOfCatalog the name of this catalog. If this value is 070 * <i>null</i>, this catalog will be given a 071 * default name. 072 */ 073 public ResourceCatalog(String nameOfCatalog) 074 { 075 super(nameOfCatalog); 076 077 owner = UserAccountable.NULL_USER_ID; 078 createdBy = UserAccountable.NULL_USER_ID; 079 createdOn = new Date(); 080 lastUpdatedBy = UserAccountable.NULL_USER_ID; 081 lastUpdatedOn = new Date(); 082 } 083 084 /** Returns {@link Identifiable#UNIDENTIFIED}. */ 085 @Override 086 protected long getIdOfUnidentified() 087 { 088 return Identifiable.UNIDENTIFIED; 089 } 090 091 @Override 092 protected ResourceGroup createMainGroup() 093 { 094 setReservedGroupName("All Resources"); 095 096 return new ResourceGroup(this); 097 } 098 099 @Override 100 public ResourceGroup createGroup() 101 { 102 return new ResourceGroup(); 103 } 104 105 /** 106 * Resets this catalog's ID, and the IDs of all its contents, 107 * to a value that represents the unidentified state. 108 * <p> 109 * This method is useful for preparing a catalog for storage in a database. 110 * The ID property (as of now, though this may change in the future) is 111 * used by our persistence mechanism to identify objects. If you are 112 * persisting this catalog for the first time, you may need to call 113 * this method before performing a save. This is especially true if 114 * you have created this source from XML, as the XML unmarshalling 115 * brings along the ID property.</p> 116 */ 117 @Override 118 public void clearId() 119 { 120 super.clearId(); 121 122 for (Resource entry : getInternalItemList()) 123 entry.clearId(); 124 } 125 126 //============================================================================ 127 // INTERFACE UserAccountable & OWNERSHIP 128 //============================================================================ 129 130 /** 131 * Sets the ID of the user who owns this catalog. 132 * 133 * @param userId the ID of the user who owns this catalog. If this value is 134 * <i>null</i> it will be replaced with 135 * {@link UserAccountable#NULL_USER_ID}. 136 */ 137 public void setOwner(Long userId) 138 { 139 owner = (userId == null) ? UserAccountable.NULL_USER_ID : userId; 140 } 141 142 public void setCreatedBy(Long userId) 143 { 144 createdBy = (userId == null) ? UserAccountable.NULL_USER_ID : userId; 145 } 146 147 public void setCreatedOn(Date d) 148 { 149 if (d != null) 150 createdOn = d; 151 } 152 153 public void setLastUpdatedBy(Long userId) 154 { 155 lastUpdatedBy = (userId == null) ? UserAccountable.NULL_USER_ID : userId; 156 } 157 158 public void setLastUpdatedOn(Date d) 159 { 160 if (d != null) 161 lastUpdatedOn = d; 162 } 163 164 /** 165 * Returns the ID of the user who owns this catalog. 166 * @return the ID of the user who owns this catalog. 167 */ 168 public Long getOwner() { return owner; } 169 public Long getCreatedBy() { return createdBy; } 170 public Date getCreatedOn() { return createdOn; } 171 public Long getLastUpdatedBy() { return lastUpdatedBy; } 172 public Date getLastUpdatedOn() { return lastUpdatedOn; } 173 174 //============================================================================ 175 // ResourceProvider Interface 176 //============================================================================ 177 178 179 /** 180 * Returns the {@code Resource} with the given {@code id}, if any. 181 * <p> 182 * If this provider holds no {@code Resource} with an ID of {@code id}, 183 * <i>null</i> is returned.</p> 184 * 185 * @param id the identifier (primary key) for a {@code Resource} in this 186 * repository. 187 * 188 * @return The {@code Resource} with the given {@code id}, or 189 * <i>null</i>, if this provider holds no such {@code Resource}. 190 * 191 * @throws RepositoryException if anything goes wrong while trying to fetch 192 * resources from this provider. 193 */ 194 public Resource findResourceById(long id) 195 throws RepositoryException 196 { 197 for (Resource r : getItems()) 198 { 199 if (r.getId() == id) 200 return r; 201 } 202 203 return null; 204 } 205 206 /** 207 * Returns the {@code Resource}(s) with the given {@code name}, if any. 208 * <p> 209 * Ideally, the returned list will contain only one resource. However, 210 * since the name is not usually used as a primary key to a resource, it 211 * is possible that the returned list may contain more than one resource. 212 * If this provider holds no {@code Resource} with a name of {@code name}, 213 * the returned list will be empty.</p> 214 * 215 * @param name the name of a {@code Resource} requested from this provider. 216 * 217 * @return The {@code Resource}s with the given {@code name}, or 218 * <i>null</i>, if this provider holds no such {@code Resource}. 219 * 220 * @throws RepositoryException if anything goes wrong while trying to fetch 221 * resources from this provider. 222 */ 223 public List<Resource> findResourceByName(String name) 224 throws RepositoryException 225 { 226 List<Resource> found = new ArrayList<Resource>(); 227 if (name != null) 228 { 229 for (Resource r : getItems()) 230 { 231 if (name.equals(r.getName())) 232 found.add(r); 233 } 234 } 235 236 return found; 237 } 238 239 /** 240 * Returns a list of all resources held by this provider. 241 * 242 * @return a list of all resources held by this provider. If the provider has 243 * no resources the returned list will be empty. 244 * 245 * @throws RepositoryException if anything goes wrong while trying to fetch 246 * resources from this provider. 247 */ 248 public List<Resource> getAllResources() 249 throws RepositoryException 250 { 251 return getItems(); 252 } 253 254 //============================================================================ 255 // TEXT 256 //============================================================================ 257 258 /** 259 * Creates a new catalog from the XML data in the given file. 260 * 261 * @param xmlFile the name of an XML file. This method will attempt to locate 262 * the file by using {@link Class#getResource(String)}. 263 * 264 * @return a new catalog from the XML data in the given file. 265 * 266 * @throws FileNotFoundException if the XML file cannot be found. 267 * 268 * @throws JAXBException if the schema file used (if any) is malformed, if 269 * the XML file cannot be read, or if the XML file is not 270 * schema-valid. 271 * 272 * @throws XMLStreamException if there is a problem opening the XML file, 273 * if the XML is not well-formed, or for some other 274 * "unexpected processing conditions". 275 */ 276 public static ResourceCatalog fromXml(String xmlFile) 277 throws JAXBException, XMLStreamException, FileNotFoundException 278 { 279 return JaxbUtility.getSharedInstance() 280 .xmlFileToObject(xmlFile, ResourceCatalog.class); 281 } 282 283 /** 284 * Creates a new catalog based on the XML data read from {@code reader}. 285 * 286 * @param reader the source of the XML data. 287 * If this value is <i>null</i>, <i>null</i> is returned. 288 * 289 * @return a new catalog based on the XML data read from {@code reader}. 290 * 291 * @throws XMLStreamException if the XML is not well-formed, 292 * or for some other "unexpected processing conditions". 293 * 294 * @throws JAXBException if anything else goes wrong during the 295 * transformation. 296 */ 297 public static ResourceCatalog fromXml(Reader reader) 298 throws JAXBException, XMLStreamException 299 { 300 return JaxbUtility.getSharedInstance() 301 .readObjectAsXmlFrom(reader, ResourceCatalog.class, null); 302 } 303 304 /** 305 * Returns an XML representation of this catalog. 306 * @return an XML representation of this catalog. 307 * @throws JAXBException if anything goes wrong during the conversion to XML. 308 */ 309 @Override 310 public String toXml() 311 throws JAXBException 312 { 313 giveItemsCatalogIds(); 314 315 return super.toXml(); 316 } 317 318 /** 319 * Writes an XML representation of this catalog to {@code writer}. 320 * @param writer the device to which XML is written. 321 * @throws JAXBException if anything goes wrong during the conversion to XML. 322 */ 323 @Override 324 public void writeAsXmlTo(Writer writer) 325 throws JAXBException 326 { 327 giveItemsCatalogIds(); 328 329 super.writeAsXmlTo(writer); 330 } 331 332 /** 333 * Creates an ID for each resource in this catalog 334 * that is unique WITHIN this catalog. This was done in order to be 335 * more user-friendly to people creating or manipulating the XML files 336 * by hand. HOWEVER, it has the drawback that this does not create 337 * a universely unique ID. Since our use case calls for the 338 * import and export of one catalog at a time, this is fine. 339 * If we want to be more general, though, we can leave the value of 340 * xmlId alone. Resource's constructor gave this property a 341 * UNIVERSALLY unique ID. We would then eliminate this method 342 * and the overrides of the XML methods above. 343 */ 344 private void giveItemsCatalogIds() 345 { 346 HashMap<String, Integer> nameMap = new HashMap<String, Integer>(); 347 348 StringUtil util = StringUtil.getInstance(); 349 350 for (Resource r : getInternalItemList()) 351 { 352 String name = util.toXmlNCName(r.getName(), '_'); 353 int count = nameMap.containsKey(name) ? nameMap.get(name) + 1 : 1; 354 nameMap.put(name, count); 355 356 r.xmlId = (count == 1) ? name : name + "_" + count; 357 } 358 } 359 360 //---------------------------------------------------------------------------- 361 // XML Helpers 362 //---------------------------------------------------------------------------- 363 364 //These methods are here solely to help JAXB do its thing. 365 366 @XmlElementWrapper 367 @XmlElement(name="resource") 368 @SuppressWarnings("unused") 369 private List<Resource> getEntries() 370 { 371 return getInternalItemList(); 372 } 373 374 @SuppressWarnings("unused") 375 private void setEntries(List<Resource> replacementList) 376 { 377 setInternalItemList(replacementList); 378 } 379 380 @XmlElementWrapper 381 @XmlElementRef(name="resourceGroup") 382 @SuppressWarnings("unused") 383 private List<ResourceGroup> getResourceGroups() 384 { 385 return getInternalGroupList(); 386 } 387 388 @SuppressWarnings("unused") 389 private void setResourceGroups(List<ResourceGroup> replacementList) 390 { 391 setInternalGroupList(replacementList); 392 } 393 394 //============================================================================ 395 // 396 //============================================================================ 397 398 @Override 399 public ResourceCatalog clone() 400 { 401 ResourceCatalog clone = null; 402 403 try { 404 clone = (ResourceCatalog)super.clone(); 405 406 clone.createdOn = (Date)this.createdOn.clone(); 407 clone.lastUpdatedOn = (Date)this.lastUpdatedOn.clone(); 408 } 409 catch (Exception ex) { 410 throw new RuntimeException(ex); 411 } 412 413 return clone; 414 } 415 416 //============================================================================ 417 // 418 //============================================================================ 419 /* 420 public static void main(String[] args) 421 { 422 ResourceBuilder builder = new ResourceBuilder(); 423 builder.setIdentifiers(true); 424 ResourceCatalog catalog = builder.makeCatalog("Random"); 425 426 try 427 { 428 System.out.println(catalog.toXml()); 429 } 430 catch (JAXBException ex) 431 { 432 System.out.println("Trouble w/ catalog.toXml. Msg:"); 433 System.out.println(ex.getMessage()); 434 ex.printStackTrace(); 435 436 System.out.println("Attempting to write XML w/out schema verification:"); 437 JaxbUtility.getSharedInstance().setLookForDefaultSchema(false); 438 try 439 { 440 System.out.println(catalog.toXml()); 441 } 442 catch (JAXBException ex2) 443 { 444 System.out.println("Still had trouble w/ catalog.toXml. Msg:"); 445 System.out.println(ex.getMessage()); 446 ex.printStackTrace(); 447 } 448 } 449 } 450 */ 451 }