001/***************************************************************************** 002 * Copyright by The HDF Group. * 003 * Copyright by the Board of Trustees of the University of Illinois. * 004 * All rights reserved. * 005 * * 006 * This file is part of the HDF Java Products distribution. * 007 * The full copyright notice, including terms governing use, modification, * 008 * and redistribution, is contained in the files COPYING and Copyright.html. * 009 * COPYING can be found at the root of the source code distribution tree. * 010 * Or, see https://support.hdfgroup.org/products/licenses.html * 011 * If you do not have access to either file, you may request a copy from * 012 * help@hdfgroup.org. * 013 ****************************************************************************/ 014 015package hdf.object; 016 017import java.util.Iterator; 018import java.util.LinkedList; 019import java.util.List; 020import java.util.Queue; 021import java.util.Stack; 022import java.util.Vector; 023 024/** 025 * Group is an abstract class. Current implementing classes are the H4Group and 026 * H5Group. This class includes general information of a group object such as 027 * members of a group and common operations on groups. 028 * <p> 029 * Members of a group may include other groups, datasets or links. 030 * 031 * @version 1.1 9/4/2007 032 * @author Peter X. Cao 033 */ 034public abstract class Group extends HObject implements MetaDataContainer { 035 036 private static final long serialVersionUID = 3913174542591568052L; 037 038 /** 039 * The list of members (Groups and Datasets) of this group in memory. 040 */ 041 private List<HObject> memberList; 042 043 /** 044 * The parent group where this group is located. The parent of the root 045 * group is null. 046 */ 047 protected Group parent; 048 049 /** 050 * Total number of members of this group in file. 051 */ 052 protected int nMembersInFile; 053 054 public static final int LINK_TYPE_HARD = 0; 055 056 public static final int LINK_TYPE_SOFT = 1; 057 058 public static final int LINK_TYPE_EXTERNAL = 64; 059 060 public static final int CRT_ORDER_TRACKED = 1; 061 062 public static final int CRT_ORDER_INDEXED = 2; 063 064 065 /** 066 * Constructs an instance of the group with specific name, path and parent 067 * group. An HDF data object must have a name. The path is the group path 068 * starting from the root. The parent group is the group where this group is 069 * located. 070 * <p> 071 * For example, in H5Group(h5file, "grp", "/groups/", pgroup), "grp" is the 072 * name of the group, "/groups/" is the group path of the group, and pgroup 073 * is the group where "grp" is located. 074 * 075 * @param theFile 076 * the file containing the group. 077 * @param grpName 078 * the name of this group, e.g. "grp01". 079 * @param grpPath 080 * the full path of this group, e.g. "/groups/". 081 * @param grpParent 082 * the parent of this group. 083 */ 084 public Group(FileFormat theFile, String grpName, String grpPath, Group grpParent) { 085 this(theFile, grpName, grpPath, grpParent, null); 086 } 087 088 /** 089 * @deprecated Not for public use in the future.<br> 090 * Using {@link #Group(FileFormat, String, String, Group)} 091 * 092 * @param theFile 093 * the file containing the group. 094 * @param grpName 095 * the name of this group, e.g. "grp01". 096 * @param grpPath 097 * the full path of this group, e.g. "/groups/". 098 * @param grpParent 099 * the parent of this group. 100 * @param oid 101 * the oid of this group. 102 */ 103 @Deprecated 104 public Group(FileFormat theFile, String grpName, String grpPath, Group grpParent, long[] oid) { 105 super(theFile, grpName, grpPath, oid); 106 107 this.parent = grpParent; 108 } 109 110 /** 111 * Clears up member list and other resources in memory for the group. Since 112 * the destructor will clear memory space, the function is usually not 113 * needed. 114 */ 115 public void clear() { 116 if (memberList != null) { 117 ((Vector<HObject>) memberList).setSize(0); 118 } 119 } 120 121 /** 122 * Adds an object to the member list of this group in memory. 123 * 124 * @param object 125 * the HObject to be added to the member list. 126 */ 127 public void addToMemberList(HObject object) { 128 if (memberList == null) { 129 int size = Math.min(getNumberOfMembersInFile(), this 130 .getFileFormat().getMaxMembers()); 131 memberList = new Vector<>(size + 5); 132 } 133 134 if ((object != null) && !memberList.contains(object)) { 135 memberList.add(object); 136 } 137 } 138 139 /** 140 * Removes an object from the member list of this group in memory. 141 * 142 * @param object 143 * the HObject (Group or Dataset) to be removed from the member 144 * list. 145 */ 146 public void removeFromMemberList(HObject object) { 147 if (memberList != null) { 148 memberList.remove(object); 149 } 150 } 151 152 /** 153 * Returns the list of members of this group. The list is an java.util.List 154 * containing HObjects. 155 * 156 * @return the list of members of this group. 157 */ 158 public List<HObject> getMemberList() { 159 FileFormat theFile = this.getFileFormat(); 160 161 if ((memberList == null) && (theFile != null)) { 162 int size = Math.min(getNumberOfMembersInFile(), this.getFileFormat().getMaxMembers()); 163 memberList = new Vector<>(size + 5); // avoid infinite loop search for groups without members 164 165 // find the memberList from the file by checking the group path and 166 // name. group may be created out of the structure tree 167 // (H4/5File.loadTree()). 168 if (theFile.getFID() < 0) { 169 try { 170 theFile.open(); 171 } // load the file structure; 172 catch (Exception ex) { 173 ; 174 } 175 } 176 177 HObject root = theFile.getRootObject(); 178 if (root == null) return memberList; 179 180 Iterator<HObject> it = ((Group) root).depthFirstMemberList().iterator(); 181 Group g = null; 182 Object uObj = null; 183 while (it.hasNext()) { 184 uObj = it.next(); 185 186 if (uObj instanceof Group) { 187 g = (Group) uObj; 188 if (g.getPath() != null) // add this check to get rid of null exception 189 { 190 if ((this.isRoot() && g.isRoot()) 191 || (this.getPath().equals(g.getPath()) && 192 g.getName().endsWith(this.getName()))) { 193 memberList = g.getMemberList(); 194 break; 195 } 196 } 197 } 198 } 199 } 200 201 return memberList; 202 } 203 204 /** 205 * @return the members of this Group in breadth-first order. 206 */ 207 public List<HObject> breadthFirstMemberList() { 208 Vector<HObject> members = new Vector<>(); 209 Queue<HObject> queue = new LinkedList<>(); 210 HObject currentObj = this; 211 212 queue.addAll(((Group) currentObj).getMemberList()); 213 214 while(!queue.isEmpty()) { 215 currentObj = queue.remove(); 216 members.add(currentObj); 217 218 if(currentObj instanceof Group && ((Group) currentObj).getNumberOfMembersInFile() > 0) { 219 queue.addAll(((Group) currentObj).getMemberList()); 220 } 221 } 222 223 return members; 224 } 225 226 /** 227 * @return the members of this Group in depth-first order. 228 */ 229 public List<HObject> depthFirstMemberList() { 230 Vector<HObject> members = new Vector<>(); 231 Stack<HObject> stack = new Stack<>(); 232 HObject currentObj = this; 233 234 // Push elements onto the stack in reverse order 235 List<HObject> list = ((Group) currentObj).getMemberList(); 236 for(int i = list.size() - 1; i >= 0; i--) { 237 stack.push(list.get(i)); 238 } 239 240 while(!stack.empty()) { 241 currentObj = stack.pop(); 242 members.add(currentObj); 243 244 if(currentObj instanceof Group && ((Group) currentObj).getNumberOfMembersInFile() > 0) { 245 list = ((Group) currentObj).getMemberList(); 246 for(int i = list.size() - 1; i >= 0; i--) { 247 stack.push(list.get(i)); 248 } 249 } 250 } 251 252 return members; 253 } 254 255 /** 256 * Sets the name of the group. 257 * <p> 258 * setName (String newName) changes the name of the group in memory and 259 * file. 260 * <p> 261 * setName() updates the path in memory for all the objects that are under 262 * the group with the new name. 263 * 264 * @param newName 265 * The new name of the group. 266 * 267 * @throws Exception if the name can not be set 268 */ 269 @Override 270 public void setName(String newName) throws Exception { 271 if (newName == null) 272 throw new IllegalArgumentException("The new name is NULL"); 273 274 super.setName(newName); 275 276 if (memberList != null) { 277 int n = memberList.size(); 278 HObject theObj = null; 279 for (int i = 0; i < n; i++) { 280 theObj = memberList.get(i); 281 theObj.setPath(this.getPath() + newName + HObject.SEPARATOR); 282 } 283 } 284 } 285 286 /** @return the parent group. */ 287 public final Group getParent() { 288 return parent; 289 } 290 291 /** 292 * Checks if it is a root group. 293 * 294 * @return true if the group is a root group; otherwise, returns false. 295 */ 296 public final boolean isRoot() { 297 return (parent == null); 298 } 299 300 /** 301 * Returns the total number of members of this group in file. 302 * 303 * Current Java applications such as HDFView cannot handle files with large 304 * numbers of objects (1,000,000 or more objects) due to JVM memory 305 * limitation. The max_members is used so that applications such as HDFView 306 * will load up to <i>max_members</i> number of objects. If the number of 307 * objects in file is larger than <i>max_members</i>, only 308 * <i>max_members</i> are loaded in memory. 309 * <p> 310 * getNumberOfMembersInFile() returns the number of objects in this group. 311 * The number of objects in memory is obtained by getMemberList().size(). 312 * 313 * @return Total number of members of this group in the file. 314 */ 315 public int getNumberOfMembersInFile() { 316 return nMembersInFile; 317 } 318 319 /** 320 * Get the HObject at the specified index in this Group's member list. 321 * @param idx The index of the HObject to get. 322 * @return The HObject at the specified index. 323 */ 324 public HObject getMember(int idx) { 325 if(memberList.size() <= 0 || idx >= memberList.size()) return null; 326 327 return memberList.get(idx); 328 } 329}