001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2013-2017 ForgeRock AS. 015 */ 016 017package org.forgerock.json.jose.jwt; 018 019import java.util.LinkedHashMap; 020import java.util.List; 021import java.util.Map; 022import java.util.Set; 023 024import org.forgerock.json.JsonValue; 025import org.forgerock.json.jose.exceptions.JwtRuntimeException; 026import org.forgerock.json.jose.utils.Utils; 027 028/** 029 * A base implementation class for a JSON Web object. 030 * <p> 031 * Provides a set of methods which are common across JWT, JWS, JWE and JWK implementations. 032 * 033 * @since 2.0.0 034 */ 035public abstract class JWObject { 036 037 private final JsonValue jsonValue; 038 039 /** 040 * Constructs a new, empty JWObject. 041 */ 042 public JWObject() { 043 this.jsonValue = new JsonValue(new LinkedHashMap<>()); 044 } 045 046 /** 047 * Checks that the given value is of an assignable type from the required class. 048 * <p> 049 * Will throw a JwtRuntimeException if the value is not of the required type 050 * 051 * @param value The value to check is of the required type. 052 * @param requiredClazz The class of the required type. 053 * @see #isValueOfType(Object, Class) 054 */ 055 protected void checkValueIsOfType(Object value, Class<?> requiredClazz) { 056 if (!requiredClazz.isAssignableFrom(value.getClass())) { 057 throw new JwtRuntimeException("Value is not of the required type. Required, " + requiredClazz.getName() 058 + ", actual, " + value.getClass().getName()); 059 } 060 } 061 062 /** 063 * Checks that the given List's type is of an assignable type from the required class. 064 * <p> 065 * Will throw a JwtRuntimeException if the value is not of the required type 066 * 067 * @param value The List to check the type is of the required type. 068 * @param requiredClazz The class of the required type. 069 * @see #checkValueIsOfType(Object, Class) 070 */ 071 protected void checkListValuesAreOfType(List<?> value, Class<?> requiredClazz) { 072 if (value.size() > 0) { 073 checkValueIsOfType(value.get(0), requiredClazz); 074 } 075 } 076 077 /** 078 * Checks to see if the given value is of an assignable type from the required class. 079 * 080 * @param value The value to check is of the required type. 081 * @param requiredClazz The class of the required type. 082 * @return <code>true</code> if the value if of the required type. 083 * @see #checkValueIsOfType(Object, Class) 084 */ 085 protected boolean isValueOfType(Object value, Class<?> requiredClazz) { 086 return requiredClazz.isAssignableFrom(value.getClass()); 087 } 088 089 /** 090 * Sets or removes the value of the specified member. 091 * <p> 092 * If the value is not null, then the value is set as the value of the given key. 093 * <p> 094 * Otherwise, if the value is null and the key already exist with a value assigned to it, then the key and its value 095 * will be removed. If the specified key is not defined, calling this method has no effect. 096 * 097 * @param key the {@code Map} key identifying the value to set or to remove. 098 * @param value the object value to assign to the member. 099 */ 100 public void put(String key, Object value) { 101 if (value != null) { 102 jsonValue.put(key, value); 103 } else if (jsonValue.isDefined(key)) { 104 jsonValue.remove(key); 105 } 106 } 107 108 /** 109 * Returns the specified item value. If no such member value exists, then a JSON value containing {@code null} is 110 * returned. 111 * 112 * @param key the {@code Map} key identifying the item to return. 113 * @return a JSON value containing the value or {@code null}. 114 */ 115 public JsonValue get(String key) { 116 return jsonValue.get(key); 117 } 118 119 /** 120 * Returns {@code true} if this JWObject contains the specified item. 121 * 122 * @param key the {@code Map} key of the item to seek. 123 * @return {@code true} if this JSON value contains the specified member. 124 */ 125 public boolean isDefined(String key) { 126 return jsonValue.isDefined(key); 127 } 128 129 /** 130 * Returns the set of keys for this JWObject's values. 131 * <p> 132 * The order of the resulting keys is undefined. If there are no values set, this method returns an empty set. 133 * 134 * @return A Set of keys. 135 */ 136 public Set<String> keys() { 137 return jsonValue.keys(); 138 } 139 140 /** 141 * Returns the {@code Map} of keys and values stored by {@link #put}. 142 * 143 * @return {@code Map} of this JWObject's keys and values. 144 */ 145 Map<String, Object> getAll() { 146 return jsonValue.asMap(); 147 } 148 149 /** 150 * Returns a string representation of the JWObject. The result is guaranteed to be valid JSON object syntax. 151 * 152 * @return A JSON String representation. 153 */ 154 @Override 155 public String toString() { 156 return Utils.writeJsonObject(jsonValue.asMap()); 157 } 158 159 /** 160 * Returns a json representation of the JWObject. 161 * 162 * @return A JSON representation. 163 */ 164 public JsonValue toJsonValue() { 165 return jsonValue.copy(); 166 } 167}