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