diff --git a/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/GetPools.java b/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/GetPools.java
new file mode 100644
index 000000000..12575995e
--- /dev/null
+++ b/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/GetPools.java
@@ -0,0 +1,67 @@
+/*
+ * VM-Operator
+ * Copyright (C) 2024 Michael N. Lipp
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.jdrupes.vmoperator.manager.events;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import org.jdrupes.vmoperator.common.VmPool;
+import org.jgrapes.core.Event;
+
+/**
+ * Gets the known pools' definitions.
+ */
+@SuppressWarnings("PMD.DataClass")
+public class GetPools extends Event> {
+
+ private String user;
+ private List roles = Collections.emptyList();
+
+ /**
+ * Return only {@link VmPool}s that are accessible by
+ * the given user or roles.
+ *
+ * @param user the user
+ * @param roles the roles
+ * @return the event
+ */
+ public GetPools accessibleFor(String user, List roles) {
+ this.user = user;
+ this.roles = roles;
+ return this;
+ }
+
+ /**
+ * Returns the user filter criterion, if set.
+ *
+ * @return the optional
+ */
+ public Optional forUser() {
+ return Optional.ofNullable(user);
+ }
+
+ /**
+ * Returns the roles criterion.
+ *
+ * @return the list
+ */
+ public List forRoles() {
+ return roles;
+ }
+}
diff --git a/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/GetVms.java b/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/GetVms.java
new file mode 100644
index 000000000..ebb19cca7
--- /dev/null
+++ b/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/GetVms.java
@@ -0,0 +1,97 @@
+/*
+ * VM-Operator
+ * Copyright (C) 2024 Michael N. Lipp
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.jdrupes.vmoperator.manager.events;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import org.jdrupes.vmoperator.common.VmDefinition;
+import org.jgrapes.core.Event;
+
+/**
+ * Gets the known VMs' definitions and channels.
+ */
+@SuppressWarnings("PMD.DataClass")
+public class GetVms extends Event> {
+
+ private String name;
+ private String user;
+ private List roles = Collections.emptyList();
+
+ /**
+ * Return only the VMs with the given name.
+ *
+ * @param name the name
+ * @return the returns the vms
+ */
+ public GetVms withName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ /**
+ * Return only {@link VmDefinition}s that are accessible by
+ * the given user or roles.
+ *
+ * @param user the user
+ * @param roles the roles
+ * @return the event
+ */
+ public GetVms accessibleFor(String user, List roles) {
+ this.user = user;
+ this.roles = roles;
+ return this;
+ }
+
+ /**
+ * Returns the name filter criterion, if set.
+ *
+ * @return the optional
+ */
+ public Optional name() {
+ return Optional.ofNullable(name);
+ }
+
+ /**
+ * Returns the user filter criterion, if set.
+ *
+ * @return the optional
+ */
+ public Optional user() {
+ return Optional.ofNullable(user);
+ }
+
+ /**
+ * Returns the roles criterion.
+ *
+ * @return the list
+ */
+ public List roles() {
+ return roles;
+ }
+
+ /**
+ * Return tuple.
+ *
+ * @param definition the definition
+ * @param channel the channel
+ */
+ public record VmData(VmDefinition definition, VmChannel channel) {
+ }
+}
diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolMonitor.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolMonitor.java
index 27dfb7d12..1864ea7df 100644
--- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolMonitor.java
+++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolMonitor.java
@@ -35,6 +35,7 @@
import org.jdrupes.vmoperator.common.K8sObserver.ResponseType;
import org.jdrupes.vmoperator.common.VmPool;
import static org.jdrupes.vmoperator.manager.Constants.VM_OP_KIND_VM_POOL;
+import org.jdrupes.vmoperator.manager.events.GetPools;
import org.jdrupes.vmoperator.manager.events.VmDefChanged;
import org.jdrupes.vmoperator.manager.events.VmPoolChanged;
import org.jdrupes.vmoperator.util.GsonPtr;
@@ -161,4 +162,18 @@ public void onVmDefChanged(VmDefChanged event) {
break;
}
}
+
+ /**
+ * Return the requested pools.
+ *
+ * @param event the event
+ */
+ @Handler
+ public void onGetPools(GetPools event) {
+ event.setResult(pools.values().stream()
+ .filter(p -> event.forUser().isEmpty() && event.forRoles().isEmpty()
+ || !p.permissionsFor(event.forUser().orElse(null),
+ event.forRoles()).isEmpty())
+ .toList());
+ }
}
diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/VmMonitor.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/VmMonitor.java
index 6c769d270..b5268a2c5 100644
--- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/VmMonitor.java
+++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/VmMonitor.java
@@ -44,10 +44,13 @@
import static org.jdrupes.vmoperator.manager.Constants.VM_OP_KIND_VM;
import static org.jdrupes.vmoperator.manager.Constants.VM_OP_NAME;
import org.jdrupes.vmoperator.manager.events.ChannelManager;
+import org.jdrupes.vmoperator.manager.events.GetVms;
+import org.jdrupes.vmoperator.manager.events.GetVms.VmData;
import org.jdrupes.vmoperator.manager.events.VmChannel;
import org.jdrupes.vmoperator.manager.events.VmDefChanged;
import org.jgrapes.core.Channel;
import org.jgrapes.core.Event;
+import org.jgrapes.core.annotation.Handler;
/**
* Watches for changes of VM definitions.
@@ -208,4 +211,21 @@ private void addDynamicData(K8sClient client, VmDefinition vmDef,
() -> "Cannot access node information: " + e.getMessage());
}
}
+
+ /**
+ * Returns the VM data.
+ *
+ * @param event the event
+ */
+ @Handler
+ public void onGetVms(GetVms event) {
+ event.setResult(channelManager.channels().stream()
+ .filter(c -> event.name().isEmpty()
+ || c.vmDefinition().name().equals(event.name().get()))
+ .filter(c -> event.user().isEmpty() && event.roles().isEmpty()
+ || !c.vmDefinition().permissionsFor(event.user().orElse(null),
+ event.roles()).isEmpty())
+ .map(c -> new VmData(c.vmDefinition(), c))
+ .toList());
+ }
}
diff --git a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java
index 4f4ef5312..8d1a71adb 100644
--- a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java
+++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java
@@ -52,8 +52,10 @@
import org.jdrupes.vmoperator.common.VmDefinition;
import org.jdrupes.vmoperator.common.VmDefinition.Permission;
import org.jdrupes.vmoperator.common.VmPool;
-import org.jdrupes.vmoperator.manager.events.ChannelTracker;
import org.jdrupes.vmoperator.manager.events.GetDisplayPassword;
+import org.jdrupes.vmoperator.manager.events.GetPools;
+import org.jdrupes.vmoperator.manager.events.GetVms;
+import org.jdrupes.vmoperator.manager.events.GetVms.VmData;
import org.jdrupes.vmoperator.manager.events.ModifyVm;
import org.jdrupes.vmoperator.manager.events.ResetVm;
import org.jdrupes.vmoperator.manager.events.VmChannel;
@@ -62,8 +64,10 @@
import org.jgrapes.core.Channel;
import org.jgrapes.core.Components;
import org.jgrapes.core.Event;
+import org.jgrapes.core.EventPipeline;
import org.jgrapes.core.Manager;
import org.jgrapes.core.annotation.Handler;
+import org.jgrapes.core.events.Start;
import org.jgrapes.http.Session;
import org.jgrapes.util.events.ConfigurationUpdate;
import org.jgrapes.util.events.KeyValueStoreQuery;
@@ -122,8 +126,7 @@ public class VmAccess extends FreeMarkerConlet {
RenderMode.Preview, RenderMode.Edit);
private static final Set MODES_FOR_GENERATED = RenderMode.asSet(
RenderMode.Preview, RenderMode.StickyPreview);
- private final ChannelTracker channelTracker = new ChannelTracker<>();
+ private EventPipeline appPipeline;
private static ObjectMapper objectMapper
= new ObjectMapper().registerModule(new JavaTimeModule());
private Class> preferredIpVersion = Inet4Address.class;
@@ -150,6 +153,16 @@ public VmAccess(Channel componentChannel) {
super(componentChannel);
}
+ /**
+ * On start.
+ *
+ * @param event the event
+ */
+ @Handler
+ public void onStart(Start event) {
+ appPipeline = event.processedBy().get();
+ }
+
/**
* Configure the component.
*
@@ -263,18 +276,24 @@ public void onConsoleConfigured(ConsoleConfigured event,
if (!syncPreviews(connection.session())) {
return;
}
-
- addMissingVms(event, connection, rendered);
+ addMissingConlets(event, connection, rendered);
}
@SuppressWarnings({ "PMD.AvoidInstantiatingObjectsInLoops",
"PMD.AvoidDuplicateLiterals" })
- private void addMissingVms(ConsoleConfigured event,
- ConsoleConnection connection, final Set rendered) {
+ private void addMissingConlets(ConsoleConfigured event,
+ ConsoleConnection connection, final Set rendered)
+ throws InterruptedException {
boolean foundMissing = false;
- for (var vmName : accessibleVms(connection)) {
+ var session = connection.session();
+ for (var vmName : appPipeline.fire(new GetVms().accessibleFor(
+ WebConsoleUtils.userFromSession(session)
+ .map(ConsoleUser::getName).orElse(null),
+ WebConsoleUtils.rolesFromSession(session).stream()
+ .map(ConsoleRole::getName).toList()))
+ .get().stream().map(d -> d.definition().name()).toList()) {
if (rendered.stream()
- .anyMatch(r -> r.type() == ResourceModel.Type.VM
+ .anyMatch(r -> r.mode() == ResourceModel.Mode.VM
&& r.name().equals(vmName))) {
continue;
}
@@ -318,7 +337,7 @@ private String storagePath(Session session, String conletId) {
protected Optional createNewState(AddConletRequest event,
ConsoleConnection connection, String conletId) throws Exception {
var model = new ResourceModel(conletId);
- model.setType(ResourceModel.Type.VM);
+ model.setMode(ResourceModel.Mode.VM);
model
.setName((String) event.properties().get(VM_NAME_PROPERTY));
String jsonState = objectMapper.writeValueAsString(model);
@@ -373,11 +392,25 @@ protected Set doRenderConlet(RenderConletRequestBase> event,
ResourceBundle resourceBundle = resourceBundle(channel.locale());
Set renderedAs = EnumSet.noneOf(RenderMode.class);
if (event.renderAs().contains(RenderMode.Edit)) {
- Template tpl = freemarkerConfig()
- .getTemplate("VmAccess-edit.ftl.html");
+ var session = channel.session();
+ var vmNames = appPipeline.fire(new GetVms().accessibleFor(
+ WebConsoleUtils.userFromSession(session)
+ .map(ConsoleUser::getName).orElse(null),
+ WebConsoleUtils.rolesFromSession(session).stream()
+ .map(ConsoleRole::getName).toList()))
+ .get().stream().map(d -> d.definition().name()).sorted()
+ .toList();
+ var poolNames = appPipeline.fire(new GetPools().accessibleFor(
+ WebConsoleUtils.userFromSession(session)
+ .map(ConsoleUser::getName).orElse(null),
+ WebConsoleUtils.rolesFromSession(session).stream()
+ .map(ConsoleRole::getName).toList()))
+ .get().stream().map(VmPool::name).sorted().toList();
+ Template tpl
+ = freemarkerConfig().getTemplate("VmAccess-edit.ftl.html");
var fmModel = fmModel(event, channel, conletId, model);
- fmModel.put("vmNames", accessibleVms(channel));
- fmModel.put("poolNames", accessiblePools(channel));
+ fmModel.put("vmNames", vmNames);
+ fmModel.put("poolNames", poolNames);
channel.respond(new OpenModalDialog(type(), conletId,
processTemplate(event, tpl, fmModel))
.addOption("cancelable", true)
@@ -391,27 +424,32 @@ protected Set doRenderConlet(RenderConletRequestBase> event,
private Set renderPreview(RenderConletRequestBase> event,
ConsoleConnection channel, String conletId, ResourceModel model)
throws TemplateNotFoundException, MalformedTemplateNameException,
- ParseException, IOException {
+ ParseException, IOException, InterruptedException {
channel.associated(PENDING, Event.class)
.ifPresent(e -> {
e.resumeHandling();
channel.setAssociated(PENDING, null);
});
- if (model.type() == ResourceModel.Type.VM && model.name() != null) {
+ var session = channel.session();
+ if (model.mode() == ResourceModel.Mode.VM && model.name() != null) {
// Remove conlet if VM definition has been removed
// or user has not at least one permission
- Optional vmDef
- = channelTracker.associated(model.name());
- if (vmDef.isEmpty()
- || vmPermissions(vmDef.get(), channel.session()).isEmpty()) {
+ Optional vmData = appPipeline.fire(new GetVms()
+ .withName(model.name()).accessibleFor(
+ WebConsoleUtils.userFromSession(session)
+ .map(ConsoleUser::getName).orElse(null),
+ WebConsoleUtils.rolesFromSession(session).stream()
+ .map(ConsoleRole::getName).toList()))
+ .get().stream().findFirst();
+ if (vmData.isEmpty()) {
channel.respond(
new DeleteConlet(conletId, Collections.emptySet()));
return Collections.emptySet();
}
}
- if (model.type() == ResourceModel.Type.POOL && model.name() != null) {
+ if (model.mode() == ResourceModel.Mode.POOL && model.name() != null) {
// Remove conlet if pool definition has been removed
// or user has not at least one permission
VmPool pool = vmPools.get(model.name());
@@ -442,12 +480,6 @@ private Set renderPreview(RenderConletRequestBase> event,
return EnumSet.of(RenderMode.Preview);
}
- private List accessibleVms(ConsoleConnection channel) {
- return channelTracker.associated().stream()
- .filter(d -> !vmPermissions(d, channel.session()).isEmpty())
- .map(d -> d.getMetadata().getName()).sorted().toList();
- }
-
private Set vmPermissions(VmDefinition vmDef,
Session session) {
var user = WebConsoleUtils.userFromSession(session)
@@ -457,12 +489,6 @@ private Set vmPermissions(VmDefinition vmDef,
return vmDef.permissionsFor(user, roles);
}
- private List accessiblePools(ConsoleConnection channel) {
- return vmPools.values().stream()
- .filter(d -> !poolPermissions(d, channel.session()).isEmpty())
- .map(d -> d.name()).sorted().toList();
- }
-
private Set poolPermissions(VmPool pool,
Session session) {
var user = WebConsoleUtils.userFromSession(session)
@@ -472,34 +498,36 @@ private Set poolPermissions(VmPool pool,
return pool.permissionsFor(user, roles);
}
- private void updateConfig(ConsoleConnection channel, ResourceModel model) {
+ private void updateConfig(ConsoleConnection channel, ResourceModel model)
+ throws InterruptedException {
channel.respond(new NotifyConletView(type(),
- model.getConletId(), "updateConfig", model.type(), model.name()));
+ model.getConletId(), "updateConfig", model.mode(), model.name()));
updateVmDef(channel, model);
}
- private void updateVmDef(ConsoleConnection channel, ResourceModel model) {
+ private void updateVmDef(ConsoleConnection channel, ResourceModel model)
+ throws InterruptedException {
if (Strings.isNullOrEmpty(model.name())) {
return;
}
- channelTracker.value(model.name()).ifPresent(item -> {
- try {
- var vmDef = item.associated();
- var data = Map.of("metadata",
- Map.of("namespace", vmDef.namespace(),
- "name", vmDef.name()),
- "spec", vmDef.spec(),
- "status", vmDef.getStatus(),
- "userPermissions",
- vmPermissions(vmDef, channel.session()).stream()
- .map(VmDefinition.Permission::toString).toList());
- channel.respond(new NotifyConletView(type(),
- model.getConletId(), "updateVmDefinition", data));
- } catch (JsonSyntaxException e) {
- logger.log(Level.SEVERE, e,
- () -> "Failed to serialize VM definition");
- }
- });
+ appPipeline.fire(new GetVms().withName(model.name())).get().stream()
+ .findFirst().map(d -> d.definition()).ifPresent(vmDef -> {
+ try {
+ var data = Map.of("metadata",
+ Map.of("namespace", vmDef.namespace(),
+ "name", vmDef.name()),
+ "spec", vmDef.spec(),
+ "status", vmDef.getStatus(),
+ "userPermissions",
+ vmPermissions(vmDef, channel.session()).stream()
+ .map(VmDefinition.Permission::toString).toList());
+ channel.respond(new NotifyConletView(type(),
+ model.getConletId(), "updateVmDefinition", data));
+ } catch (JsonSyntaxException e) {
+ logger.log(Level.SEVERE, e,
+ () -> "Failed to serialize VM definition");
+ }
+ });
}
@Override
@@ -519,20 +547,15 @@ protected void doConletDeleted(ConletDeleted event,
* @param event the event
* @param channel the channel
* @throws IOException
+ * @throws InterruptedException
*/
@Handler(namedChannels = "manager")
@SuppressWarnings({ "PMD.ConfusingTernary", "PMD.CognitiveComplexity",
"PMD.AvoidInstantiatingObjectsInLoops", "PMD.AvoidDuplicateLiterals",
"PMD.ConfusingArgumentToVarargsMethod" })
public void onVmDefChanged(VmDefChanged event, VmChannel channel)
- throws IOException {
+ throws IOException, InterruptedException {
var vmDef = event.vmDefinition();
- var vmName = vmDef.name();
- if (event.type() == K8sObserver.ResponseType.DELETED) {
- channelTracker.remove(vmName);
- } else {
- channelTracker.put(vmName, channel, vmDef);
- }
// Update known conlets
for (var entry : conletIdsByConsoleConnection().entrySet()) {
@@ -540,8 +563,8 @@ public void onVmDefChanged(VmDefChanged event, VmChannel channel)
for (var conletId : entry.getValue()) {
var model = stateFromSession(connection.session(), conletId);
if (model.isEmpty()
- || model.get().type() != ResourceModel.Type.VM
- || !Objects.areEqual(model.get().name(), vmName)) {
+ || model.get().mode() != ResourceModel.Mode.VM
+ || !Objects.areEqual(model.get().name(), vmDef.name())) {
continue;
}
if (event.type() == K8sObserver.ResponseType.DELETED
@@ -577,7 +600,7 @@ public void onVmPoolChanged(VmPoolChanged event) {
for (var conletId : entry.getValue()) {
var model = stateFromSession(connection.session(), conletId);
if (model.isEmpty()
- || model.get().type() != ResourceModel.Type.POOL
+ || model.get().mode() != ResourceModel.Mode.POOL
|| !Objects.areEqual(model.get().name(), poolName)) {
continue;
}
@@ -605,13 +628,13 @@ protected void doUpdateConletState(NotifyConletModel event,
}
// Handle command for selected VM
- var both = Optional.ofNullable(model.name())
- .flatMap(vm -> channelTracker.value(vm));
- if (both.isEmpty()) {
+ var vmData = appPipeline.fire(new GetVms().withName(model.name())).get()
+ .stream().findFirst();
+ if (vmData.isEmpty()) {
return;
}
- var vmChannel = both.get().channel();
- var vmDef = both.get().associated();
+ var vmChannel = vmData.get().channel();
+ var vmDef = vmData.get().definition();
var vmName = vmDef.metadata().getName();
var perms = vmPermissions(vmDef, channel.session());
var resourceBundle = resourceBundle(channel.locale());
@@ -656,9 +679,9 @@ protected void doUpdateConletState(NotifyConletModel event,
"PMD.UseLocaleWithCaseConversions" })
private void selectResource(NotifyConletModel event,
ConsoleConnection channel, ResourceModel model)
- throws JsonProcessingException {
+ throws JsonProcessingException, InterruptedException {
try {
- model.setType(ResourceModel.Type
+ model.setMode(ResourceModel.Mode
.valueOf(event. param(0).toUpperCase()));
model.setName(event.param(1));
String jsonState = objectMapper.writeValueAsString(model);
@@ -672,7 +695,13 @@ private void selectResource(NotifyConletModel event,
private void openConsole(String vmName, ConsoleConnection connection,
ResourceModel model, String password) {
- var vmDef = channelTracker.associated(vmName).orElse(null);
+ VmDefinition vmDef;
+ try {
+ vmDef = appPipeline.fire(new GetVms().withName(model.name())).get()
+ .stream().findFirst().map(VmData::definition).orElse(null);
+ } catch (InterruptedException e) {
+ return;
+ }
if (vmDef == null) {
return;
}
@@ -771,11 +800,11 @@ public static class ResourceModel extends ConletBaseModel {
* The Enum ResourceType.
*/
@SuppressWarnings("PMD.ShortVariable")
- public enum Type {
+ public enum Mode {
VM, POOL
}
- private Type type;
+ private Mode mode;
private String name;
/**
@@ -807,27 +836,29 @@ public void setName(String name) {
}
/**
+ * Returns the mode.
+ *
* @return the resourceType
*/
- @JsonGetter("type")
- public Type type() {
- return type;
+ @JsonGetter("mode")
+ public Mode mode() {
+ return mode;
}
/**
- * Sets the type.
+ * Sets the mode.
*
- * @param type the resource type to set
+ * @param mode the resource mode to set
*/
- public void setType(Type type) {
- this.type = type;
+ public void setMode(Mode mode) {
+ this.mode = mode;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
- result = prime * result + java.util.Objects.hash(name, type);
+ result = prime * result + java.util.Objects.hash(name, mode);
return result;
}
@@ -844,14 +875,14 @@ public boolean equals(Object obj) {
}
ResourceModel other = (ResourceModel) obj;
return java.util.Objects.equals(name, other.name)
- && type == other.type;
+ && mode == other.mode;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder(50);
- builder.append("AccessModel [resourceType=").append(type)
- .append(", resourceName=").append(name).append(']');
+ builder.append("AccessModel [mode=").append(mode)
+ .append(", name=").append(name).append(']');
return builder.toString();
}