001/* 002 * JDrupes Builder 003 * Copyright (C) 2025, 2026 Michael N. Lipp 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <https://www.gnu.org/licenses/>. 017 */ 018 019package org.jdrupes.builder.core; 020 021import java.util.Objects; 022import java.util.Optional; 023import org.jdrupes.builder.api.Proxyable; 024import org.jdrupes.builder.api.Resource; 025import org.jdrupes.builder.api.ResourceType; 026 027/// A base class for [Resource]s. 028/// 029public abstract class ResourceObject implements Resource, Proxyable { 030 031 private final ResourceType<?> type; 032 private String name; 033 private boolean isLocked; 034 035 /// Create a new instance. 036 /// 037 protected ResourceObject() { 038 this.type = new ResourceType<>(getClass(), null); 039 } 040 041 /// Create a new instance. 042 /// 043 /// @param type the type 044 /// 045 protected ResourceObject(ResourceType<?> type) { 046 this.type = Objects.requireNonNull(type); 047 } 048 049 @Override 050 public ResourceType<?> type() { 051 return type; 052 } 053 054 @Override 055 public Optional<String> name() { 056 return Optional.ofNullable(name); 057 } 058 059 /// Sets the name of the resource. 060 /// 061 /// @param name the name 062 /// @return the resource object 063 /// 064 public ResourceObject name(String name) { 065 if (isLocked) { 066 throw new IllegalStateException( 067 "Name may only be set once immediately after creation."); 068 } 069 isLocked = true; 070 this.name = name; 071 return this; 072 } 073 074 /// Checks if the instance has been used in a comparison (`hashCode` 075 /// or `equals`) and is therefore locked for further modifications. 076 /// 077 /// @return true, if is locked 078 /// 079 public boolean isLocked() { 080 return isLocked; 081 } 082 083 @Override 084 public int hashCode() { 085 isLocked = true; 086 return Objects.hash(type(), name()); 087 } 088 089 @Override 090 public boolean equals(Object obj) { 091 isLocked = true; 092 if (this == obj) { 093 return true; 094 } 095 if (obj == null) { 096 return false; 097 } 098 return (obj instanceof ResourceObject other) 099 && Objects.equals(type(), other.type()) 100 && Objects.equals(name(), other.name()); 101 } 102 103 @Override 104 public String toString() { 105 return type() + name().map(n -> ":" + n).orElse("") 106 + " (" + asOfLocalized() + ")"; 107 } 108}