001/* 002 * PermissionsEx 003 * Copyright (C) zml and PermissionsEx contributors 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package ca.stellardrift.permissionsex.datastore.sql; 018 019import ca.stellardrift.permissionsex.datastore.DataStoreContext; 020import ca.stellardrift.permissionsex.subject.SubjectRef; 021import ca.stellardrift.permissionsex.subject.SubjectType; 022import org.checkerframework.checker.nullness.qual.Nullable; 023 024import java.util.Objects; 025 026public class SqlSubjectRef<I> implements SubjectRef<I> { 027 private volatile int id; 028 private @Nullable volatile SubjectRef<I> resolved = null; 029 private final DataStoreContext context; 030 private final String type, identifier; 031 032 SqlSubjectRef(final DataStoreContext context, final int id, final String type, final String identifier) { 033 this.context = context; 034 this.id = id; 035 this.type = type; 036 this.identifier = identifier; 037 } 038 039 SqlSubjectRef(final SubjectRef<I> existing) { 040 this.id = SqlConstants.UNALLOCATED; 041 this.context = null; 042 this.type = existing.type().name(); 043 this.identifier = null; 044 this.resolved = SubjectRef.mapKeySafe(existing); 045 } 046 047 public static <I> SqlSubjectRef<I> unresolved(final DataStoreContext context, final String type, final String name) { 048 return new SqlSubjectRef<>(context, SqlConstants.UNALLOCATED, type, name); 049 } 050 051 public int id() { 052 if (id == SqlConstants.UNALLOCATED) { 053 throw new IllegalStateException("Unallocated SubjectRef tried to be used!"); 054 } 055 return id; 056 } 057 058 public void id(int id) { 059 this.id = id; 060 } 061 062 boolean isUnallocated() { 063 return id == SqlConstants.UNALLOCATED; 064 } 065 066 public String rawType() { 067 return type; 068 } 069 070 public String rawIdentifier() { 071 if (this.identifier == null) { 072 final @Nullable SubjectRef<I> resolved = this.resolved; 073 if (resolved == null) { 074 throw new IllegalStateException("Unable to get an identifier for this subject ref"); 075 } 076 return resolved.serializedIdentifier(); 077 } 078 return this.identifier; 079 } 080 081 @Override 082 public String serializedIdentifier() { 083 final @Nullable SubjectRef<?> resolved = this.resolved; 084 if (resolved != null) { 085 return resolved.serializedIdentifier(); 086 } else { 087 return this.identifier; 088 } 089 } 090 091 @Override 092 public SubjectType<I> type() { 093 return this.resolved().type(); 094 } 095 096 @Override 097 public I identifier() { 098 return this.resolved().identifier(); 099 } 100 101 @SuppressWarnings({"unchecked"}) 102 public SubjectRef<I> resolved() { 103 if (this.resolved != null) { 104 return this.resolved; 105 } 106 return this.resolved = (SubjectRef<I>) this.context.deserializeSubjectRef(this.type, this.identifier); 107 } 108 109 @Override 110 public boolean equals(final Object other) { 111 if (this == other) return true; 112 if (!(other instanceof SqlSubjectRef)) return false; 113 final SqlSubjectRef<?> that = (SqlSubjectRef<?>) other; 114 return Objects.equals(type, that.type) && 115 Objects.equals(identifier, that.identifier); 116 } 117 118 @Override 119 public int hashCode() { 120 return Objects.hash(this.type, this.identifier); 121 } 122 123 @Override 124 public String toString() { 125 return "SubjectRef{id=" + (this.id == SqlConstants.UNALLOCATED ? "<unallocated>" : this.id) 126 + ",type=" + this.type 127 + ",identifier=" + this.identifier 128 + "}"; 129 } 130 131 public static <I> SqlSubjectRef<I> from(final SubjectRef<I> existing) { 132 if (existing instanceof SqlSubjectRef<?>) { 133 return (SqlSubjectRef<I>) existing; 134 } else { 135 return new SqlSubjectRef<>(existing); 136 } 137 } 138}