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-2015 ForgeRock AS. 015 */ 016 017package org.forgerock.json.jose.jwt; 018 019import org.forgerock.json.JsonValue; 020import org.forgerock.json.jose.exceptions.JwtRuntimeException; 021 022import java.util.LinkedHashMap; 023import java.util.List; 024import java.util.Map; 025import java.util.Set; 026 027/** 028 * A base implementation class for a JSON Web object. 029 * <p> 030 * Provides a set of methods which are common across JWT, JWS, JWE and JWK implementations. 031 * 032 * @since 2.0.0 033 */ 034public abstract class JWObject { 035 036 private final JsonValue jsonValue; 037 038 /** 039 * Constructs a new, empty JWObject. 040 */ 041 public JWObject() { 042 this.jsonValue = new JsonValue(new LinkedHashMap<>()); 043 } 044 045 /** 046 * Checks that the given value is of an assignable type from the required class. 047 * <p> 048 * Will throw a JwtRuntimeException if the value is not of the required type 049 * 050 * @param value The value to check is of the required type. 051 * @param requiredClazz The class of the required type. 052 * @see #isValueOfType(Object, Class) 053 */ 054 protected void checkValueIsOfType(Object value, Class<?> requiredClazz) { 055 if (!requiredClazz.isAssignableFrom(value.getClass())) { 056 throw new JwtRuntimeException("Value is not of the required type. Required, " + requiredClazz.getName() 057 + ", actual, " + value.getClass().getName()); 058 } 059 } 060 061 /** 062 * Checks that the given List's type is of an assignable type from the required class. 063 * <p> 064 * Will throw a JwtRuntimeException if the value is not of the required type 065 * 066 * @param value The List to check the type is of the required type. 067 * @param requiredClazz The class of the required type. 068 * @see #checkValueIsOfType(Object, Class) 069 */ 070 protected void checkListValuesAreOfType(List<?> value, Class<?> requiredClazz) { 071 if (value.size() > 0) { 072 checkValueIsOfType(value.get(0), requiredClazz); 073 } 074 } 075 076 /** 077 * Checks to see if the given value is of an assignable type from the required class. 078 * 079 * @param value The value to check is of the required type. 080 * @param requiredClazz The class of the required type. 081 * @return <code>true</code> if the value if of the required type. 082 * @see #checkValueIsOfType(Object, Class) 083 */ 084 protected boolean isValueOfType(Object value, Class<?> requiredClazz) { 085 return requiredClazz.isAssignableFrom(value.getClass()); 086 } 087 088 /** 089 * Sets or removes the value of the specified member. 090 * <p> 091 * If the value is not null, then the value is set as the value of the given key. 092 * <p> 093 * Otherwise, if the value is null and the key already exist with a value assigned to it, then the key and its value 094 * will be removed. If the specified key is not defined, calling this method has no effect. 095 * 096 * @param key the {@code Map} key identifying the value to set or to remove. 097 * @param value the object value to assign to the member. 098 */ 099 public void put(String key, Object value) { 100 if (value != null) { 101 jsonValue.put(key, value); 102 } else if (jsonValue.isDefined(key)) { 103 jsonValue.remove(key); 104 } 105 } 106 107 /** 108 * Returns the specified item value. If no such member value exists, then a JSON value containing {@code null} is 109 * returned. 110 * 111 * @param key the {@code Map} key identifying the item to return. 112 * @return a JSON value containing the value or {@code null}. 113 */ 114 public JsonValue get(String key) { 115 return jsonValue.get(key); 116 } 117 118 /** 119 * Returns {@code true} if this JWObject contains the specified item. 120 * 121 * @param key the {@code Map} key of the item to seek. 122 * @return {@code true} if this JSON value contains the specified member. 123 */ 124 public boolean isDefined(String key) { 125 return jsonValue.isDefined(key); 126 } 127 128 /** 129 * Returns the set of keys for this JWObject's values. 130 * <p> 131 * The order of the resulting keys is undefined. If there are no values set, this method returns an empty set. 132 * 133 * @return A Set of keys. 134 */ 135 public Set<String> keys() { 136 return jsonValue.keys(); 137 } 138 139 /** 140 * Returns the {@code Map} of keys and values stored by {@link #put}. 141 * 142 * @return {@code Map} of this JWObject's keys and values. 143 */ 144 Map<String, Object> getAll() { 145 return jsonValue.asMap(); 146 } 147 148 /** 149 * Returns a string representation of the JWObject. The result resembles-but is not guaranteed to conform to-JSON 150 * syntax. 151 * 152 * @return A JSON String representation. 153 */ 154 @Override 155 public String toString() { 156 return jsonValue.toString(); 157 } 158}