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