Skip to content

Commit da97e3f

Browse files
committed
listing labels viea restApi
1 parent 0b30436 commit da97e3f

15 files changed

Lines changed: 799 additions & 19 deletions

File tree

modules/chimera/src/main/java/org/dcache/chimera/FileSystemProvider.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,19 @@ DirectoryStreamB<ChimeraDirectoryEntry> newDirectoryStream(FsInode dir)
174174
DirectoryStreamB<ChimeraDirectoryEntry> virtualDirectoryStream(FsInode dir, String labelname)
175175
throws ChimeraFsException;
176176

177+
/**
178+
* Returns {@link DirectoryStreamB} of ChimeraDirectoryEntry in the directory.
179+
* <p>
180+
* The returned stream may keep system resources allocated. The try-with-resources construct
181+
* should be used to ensure that the stream's close method is invoked after the stream
182+
* operations are completed.
183+
*
184+
* @param dir inode of the directory to list
185+
* @return stream of directory entries
186+
*/
187+
DirectoryStreamB<ChimeraDirectoryEntry> listLabelsStream(FsInode dir)
188+
throws ChimeraFsException;
189+
177190
void remove(String path) throws ChimeraFsException;
178191

179192
/**

modules/chimera/src/main/java/org/dcache/chimera/FsInode.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,10 @@ public DirectoryStreamB<ChimeraDirectoryEntry> virtualDirectoryStream(String lab
435435
return _fs.virtualDirectoryStream(this, labelname);
436436
}
437437

438+
public DirectoryStreamB<ChimeraDirectoryEntry> listLabelsStream() throws ChimeraFsException {
439+
return _fs.listLabelsStream(this);
440+
}
441+
438442
public String getId() throws ChimeraFsException {
439443
Stat stat = _stat;
440444
return (stat != null) ? stat.getId() : _fs.inode2id(this);

modules/chimera/src/main/java/org/dcache/chimera/JdbcFs.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,14 @@ public DirectoryStreamB<ChimeraDirectoryEntry> virtualDirectoryStream(FsInode di
563563
return _sqlDriver.virtualDirectoryStream(dir, labelname);
564564
}
565565

566+
567+
@Override
568+
public DirectoryStreamB<ChimeraDirectoryEntry> listLabelsStream(FsInode dir) throws ChimeraFsException {
569+
return _sqlDriver.labelsDirectoryStream(dir);
570+
}
571+
572+
573+
566574
@Override
567575
public void remove(String path) throws ChimeraFsException {
568576

modules/dcache-chimera/src/main/java/org/dcache/chimera/namespace/ChimeraNameSpaceProvider.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1391,6 +1391,47 @@ public void listVirtualDirectory(Subject subject, String path, Range<Integer> ra
13911391
}
13921392
}
13931393

1394+
1395+
@Override
1396+
public void listLabels(Subject subject, String path, Range<Integer> range,
1397+
Set<FileAttribute> attrs, ListHandler handler)
1398+
throws CacheException
1399+
{
1400+
try {
1401+
int counter = 0;
1402+
//TODO check permissions
1403+
try (DirectoryStreamB<ChimeraDirectoryEntry> dirStream = FsInode.getRoot(_fs)
1404+
.listLabelsStream()) {
1405+
for (ChimeraDirectoryEntry entry : dirStream) {
1406+
try {
1407+
String name = entry.getName();
1408+
if (!name.equals(".") && !name.equals("..") &&
1409+
range.contains(counter++)) {
1410+
// FIXME: actually, ChimeraDirectoryEntry
1411+
// already contains most of attributes
1412+
1413+
FileAttributes fa =
1414+
attrs.isEmpty()
1415+
? null
1416+
: getFileAttributes(new ExtendedInode(_fs, entry.getInode()), attrs);
1417+
handler.addEntry(name, fa);
1418+
}
1419+
} catch (FileNotFoundChimeraFsException e) {
1420+
/* Not an error; files may be deleted during the
1421+
* list operation.
1422+
*/
1423+
}
1424+
}
1425+
}
1426+
1427+
} catch (FileNotFoundChimeraFsException e) {
1428+
throw new FileNotFoundCacheException("No such file or directory: " + path);
1429+
} catch (IOException e) {
1430+
LOGGER.error("Exception in list: {}", e.getMessage());
1431+
throw new CacheException(CacheException.UNEXPECTED_SYSTEM_EXCEPTION, e.getMessage());
1432+
}
1433+
}
1434+
13941435
private ExtendedInode mkdir(Subject subject, ExtendedInode parent, String name, int uid,
13951436
int gid, int mode)
13961437
throws ChimeraFsException, CacheException {
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* dCache - http://www.dcache.org/
3+
*
4+
* Copyright (C) 2025 Deutsches Elektronen-Synchrotron
5+
*
6+
* This program is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU Affero General Public License as
8+
* published by the Free Software Foundation, either version 3 of the
9+
* License, or (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Affero General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Affero General Public License
17+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
package org.dcache.restful.providers;
20+
21+
import io.swagger.annotations.ApiModel;
22+
import io.swagger.annotations.ApiModelProperty;
23+
import java.util.HashSet;
24+
import java.util.Set;
25+
26+
@ApiModel(description = "Specifies all existing lables")
27+
public class JsonListLabels {
28+
29+
30+
@ApiModelProperty("All existing labels.")
31+
private Set<String> labels;
32+
33+
34+
public void setLabels(Set<String> labelnames) {
35+
if (labelnames == null) {
36+
return;
37+
}
38+
if (labels == null) {
39+
labels = new HashSet();
40+
}
41+
labels.addAll(labelnames);
42+
}
43+
44+
public Set<String> getLabels() {
45+
return labels == null ? new HashSet() : labels;
46+
}
47+
}

modules/dcache-frontend/src/main/java/org/dcache/restful/resources/labels/LabelsResources.java

Lines changed: 81 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import io.swagger.annotations.ApiResponses;
3434
import io.swagger.annotations.Authorization;
3535
import java.util.ArrayList;
36+
import java.util.HashSet;
3637
import java.util.List;
3738
import java.util.Set;
3839
import javax.inject.Inject;
@@ -56,13 +57,11 @@
5657
import org.dcache.namespace.FileAttribute;
5758
import org.dcache.poolmanager.PoolMonitor;
5859
import org.dcache.restful.providers.JsonFileAttributes;
60+
import org.dcache.restful.providers.JsonListLabels;
5961
import org.dcache.restful.util.HttpServletRequests;
6062
import org.dcache.restful.util.RequestUser;
6163
import org.dcache.restful.util.namespace.NamespaceUtils;
62-
import org.dcache.util.list.DirectoryEntry;
63-
import org.dcache.util.list.DirectoryStream;
64-
import org.dcache.util.list.ListDirectoryHandler;
65-
import org.dcache.util.list.VirtualDirectoryListHandler;
64+
import org.dcache.util.list.*;
6665
import org.slf4j.Logger;
6766
import org.slf4j.LoggerFactory;
6867
import org.springframework.stereotype.Component;
@@ -95,6 +94,9 @@ public class LabelsResources {
9594
@Inject
9695
private VirtualDirectoryListHandler virtualDirectoryListHandler;
9796

97+
@Inject
98+
private LabelsListHandler labelsListHandler;
99+
98100
@Inject
99101
@Named("pool-manager-stub")
100102
private CellStub poolmanager;
@@ -103,7 +105,78 @@ public class LabelsResources {
103105
@Named("pinManagerStub")
104106
private CellStub pinmanager;
105107

108+
@GET
109+
@ApiOperation(value = "List all existing labels.",
110+
notes = "The method offers the possibility to list the list of all existing labels.")
111+
@ApiResponses({
112+
@ApiResponse(code = 401, message = "Unauthorized"),
113+
@ApiResponse(code = 403, message = "Forbidden"),
114+
@ApiResponse(code = 404, message = "Not Found"),
115+
@ApiResponse(code = 500, message = "Internal Server Error"),
116+
})
117+
@Produces(MediaType.APPLICATION_JSON)
118+
public JsonListLabels getListLabels(
119+
@ApiParam("Limit number of replies in labels listing.")
120+
@QueryParam("limit") String limit,
121+
@ApiParam("Number of entries to skip in labels listing.")
122+
@QueryParam("offset") String offset) throws CacheException {
123+
124+
JsonListLabels labels = new JsonListLabels();
125+
126+
Set<FileAttribute> attributes =
127+
NamespaceUtils.getRequestedAttributes(false,
128+
false,
129+
false,
130+
false,
131+
false);
132+
133+
FsPath path = pathMapper.asDcachePath(request, "/", ForbiddenException::new);
134+
135+
136+
Range<Integer> range;
137+
try {
138+
int lower = (offset == null) ? 0 : Integer.parseInt(offset);
139+
int ceiling = (limit == null) ? Integer.MAX_VALUE : Integer.parseInt(limit);
140+
if (ceiling < 0 || lower < 0) {
141+
throw new BadRequestException("limit and offset can not be less than zero.");
142+
}
143+
range = (Integer.MAX_VALUE - lower < ceiling) ? Range.atLeast(lower)
144+
: Range.closedOpen(lower, lower + ceiling);
145+
} catch (NumberFormatException e) {
146+
throw new BadRequestException("limit and offset must be an integer value.");
147+
}
148+
try {
149+
DirectoryStream stream = labelsListHandler.listLabels(
150+
HttpServletRequests.roleAwareSubject(request),
151+
HttpServletRequests.roleAwareRestriction(request),
152+
path,
153+
range,
154+
attributes);
155+
106156

157+
Set<String> labelsList = new HashSet<>();
158+
159+
for (DirectoryEntry entry : stream) {
160+
String labelName = entry.getName();
161+
labelsList.add(labelName);
162+
}
163+
164+
165+
labels.setLabels(labelsList);
166+
167+
168+
} catch (PermissionDeniedCacheException e) {
169+
if (RequestUser.isAnonymous()) {
170+
throw new NotAuthorizedException(e);
171+
} else {
172+
throw new ForbiddenException(e);
173+
}
174+
} catch (CacheException | InterruptedException ex) {
175+
LOGGER.warn(Exceptions.meaningfulMessage(ex));
176+
throw new InternalServerErrorException(ex);
177+
}
178+
return labels;
179+
}
107180

108181
@GET
109182
@ApiOperation(value = "Find metadata and optionally virtual directory contents.",
@@ -145,6 +218,7 @@ public JsonFileAttributes getFileAttributes(@ApiParam("Path of file or directory
145218
false,
146219
false,
147220
false);
221+
System.out.println("test " + requestPath);
148222

149223
FsPath path = pathMapper.asDcachePath(request, requestPath, ForbiddenException::new);
150224

@@ -161,6 +235,9 @@ public JsonFileAttributes getFileAttributes(@ApiParam("Path of file or directory
161235
throw new BadRequestException("limit and offset must be an integer value.");
162236
}
163237
try {
238+
239+
System.out.println("test " + requestPath);
240+
164241
List<JsonFileAttributes> children = new ArrayList<>();
165242

166243
DirectoryStream stream = virtualDirectoryListHandler.listVirtualDirectory(

modules/dcache-frontend/src/main/resources/org/dcache/frontend/frontend.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,15 @@
9797
</bean>
9898
</constructor-arg>
9999
</bean>
100+
101+
<bean id="labels-list-handler" class="org.dcache.util.list.LabelsListHandler">
102+
<description>Client stub for directory listing</description>
103+
<constructor-arg>
104+
<bean class="diskCacheV111.util.PnfsHandler">
105+
<constructor-arg ref="pnfs-stub"/>
106+
</bean>
107+
</constructor-arg>
108+
</bean>
100109
<bean id="path-mapper" class="org.dcache.http.PathMapper">
101110
<description>Mapping between request paths and dCache paths</description>
102111
<property name="rootPath" value="${frontend.root}"/>

0 commit comments

Comments
 (0)