001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. 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 org.apache.juneau.http.header; 018 019import static org.apache.juneau.commons.utils.CollectionUtils.*; 020import static org.apache.juneau.commons.utils.StringUtils.*; 021import static org.apache.juneau.commons.utils.Utils.*; 022 023import java.util.*; 024import java.util.stream.*; 025 026import org.apache.juneau.commons.utils.*; 027import org.apache.juneau.http.annotation.*; 028 029/** 030 * Represents a parsed <l>Thrown</l> HTTP response header. 031 * 032 * <p> 033 * Contains exception information including name and optionally a message. 034 * 035 * <h5 class='figure'>Example</h5> 036 * <p class='bcode'> 037 * Thrown: org.apache.juneau.http.response.NotFound;Resource was not found 038 * </p> 039 * 040 * <p> 041 * This header isn't part of the RFC2616 specification, but is provided to allow for Java exception information 042 * to be delivered to remote REST Java interfaces. 043 * 044 * <p> 045 * This header supports comma-delimited values for multiple thrown values. 046 * <p class='bcode'> 047 * Thrown: org.apache.juneau.http.response.NotFound;Resource was not found,java.lang.RuntimeException;foo 048 * </p> 049 * 050 * <p> 051 * Note that this is equivalent to specifying multiple header values. 052 * <p class='bcode'> 053 * Thrown: org.apache.juneau.http.response.NotFound;Resource was not found 054 * Thrown: java.lang.RuntimeException;foo 055 * </p> 056 * 057 * <h5 class='section'>See Also:</h5><ul> 058 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestCommonBasics">juneau-rest-common Basics</a> 059 * </ul> 060 * 061 * @serial exclude 062 */ 063@Header("Thrown") 064public class Thrown extends BasicCsvHeader { 065 /** 066 * Represents a single entry in this header. 067 */ 068 public static class Part { 069 070 String className, message; 071 String value; 072 073 /** 074 * Constructor. 075 * 076 * @param value The header part value. 077 */ 078 public Part(String value) { 079 this.value = value; 080 var i = value.indexOf(';'); 081 this.className = urlDecode(i == -1 ? value.trim() : value.substring(0, i).trim()); 082 this.message = urlDecode(i == -1 ? null : value.substring(i + 1).trim()); 083 } 084 085 /** 086 * Constructor. 087 * 088 * @param value The throwable to create the header part value from. 089 */ 090 public Part(Throwable value) { 091 this.className = cn(value); 092 this.message = value.getMessage(); 093 this.value = urlEncode(className) + ';' + urlEncode(value.getMessage()); 094 } 095 096 /** 097 * Returns the message portion of the header. 098 * 099 * @return The message portion of the header, or <jk>null</jk> if not there. 100 */ 101 public String getClassName() { return className; } 102 103 /** 104 * Returns the message portion of the header. 105 * 106 * @return The message portion of the header, or <jk>null</jk> if not there. 107 */ 108 public String getMessage() { return message; } 109 110 @Override /* Overridden from Object */ 111 public String toString() { 112 return value; 113 } 114 } 115 116 private static final long serialVersionUID = 1L; 117 118 private static final String NAME = "Thrown"; 119 120 /** 121 * An empty unmodifiable Thrown header. 122 */ 123 public static final Thrown EMPTY = new Thrown((String)null); 124 125 /** 126 * Static creator. 127 * 128 * @param value 129 * The header value. 130 * <br>Can be <jk>null</jk>. 131 * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>. 132 */ 133 public static Thrown of(String value) { 134 return value == null ? null : new Thrown(value); 135 } 136 137 /** 138 * Static creator. 139 * 140 * @param values 141 * The header value. 142 * <br>Can be <jk>null</jk>. 143 * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>. 144 */ 145 public static Thrown of(Throwable...values) { 146 return new Thrown(l(values).stream().map(Part::new).collect(Collectors.toList())); 147 } 148 149 private final List<Part> value; 150 151 /** 152 * Constructor. 153 * 154 * @param value 155 * The header value. 156 */ 157 public Thrown(List<Part> value) { 158 super(NAME, StringUtils.join(value, ", ")); 159 this.value = u(value); 160 } 161 162 /** 163 * Constructor. 164 * 165 * @param value 166 * The header value. 167 */ 168 public Thrown(String value) { 169 super(NAME, value); 170 List<Part> l = list(); 171 StringUtils.split(value, x -> l.add(new Part(x))); 172 this.value = value == null ? null : u(l); 173 } 174 175 /** 176 * Returns the class name portion of the header. 177 * 178 * @return The class name portion of the header, or <jk>null</jk> if not there. 179 */ 180 public Optional<List<Part>> asParts() { 181 return opt(value); 182 } 183}