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 2010–2011 ApexIdentity Inc. 015 * Portions Copyright 2011-2014 ForgeRock AS. 016 */ 017 018package org.forgerock.openig.handler; 019 020import static org.forgerock.openig.util.Json.*; 021import static org.forgerock.util.Utils.*; 022 023import java.io.IOException; 024import java.util.List; 025import java.util.Map; 026 027import org.forgerock.json.fluent.JsonValue; 028import org.forgerock.openig.el.Expression; 029import org.forgerock.openig.heap.GenericHeaplet; 030import org.forgerock.openig.heap.HeapException; 031import org.forgerock.openig.http.Exchange; 032import org.forgerock.openig.http.HttpUtil; 033import org.forgerock.openig.http.Response; 034import org.forgerock.openig.util.CaseInsensitiveMap; 035import org.forgerock.openig.util.MultiValueMap; 036 037/** 038 * Creates a static response in an HTTP exchange. 039 */ 040public class StaticResponseHandler extends GenericHandler { 041 042 /** The response status code (e.g. 200). */ 043 private final Integer status; 044 045 /** The response status reason (e.g. "OK"). */ 046 private final String reason; 047 048 /** Protocol version (e.g. {@code "HTTP/1.1"}. */ 049 private final String version; 050 051 /** Message header fields whose values are expressions that are evaluated. */ 052 private final MultiValueMap<String, Expression> headers = 053 new MultiValueMap<String, Expression>(new CaseInsensitiveMap<List<Expression>>()); 054 055 /** The message entity expression. */ 056 private final Expression entity; 057 058 /** 059 * Constructor. 060 * 061 * @param status 062 * The response status to set. 063 * @param reason 064 * The response status reason to set. 065 */ 066 public StaticResponseHandler(final Integer status, final String reason) { 067 this(status, reason, null, null); 068 } 069 070 /** 071 * Constructor. 072 * 073 * @param status 074 * The response status to set. 075 * @param reason 076 * The response status reason to set. 077 * @param version 078 * The protocol version. 079 * @param entity 080 * The message entity expression. 081 */ 082 public StaticResponseHandler(final Integer status, final String reason, final String version, 083 final Expression entity) { 084 super(); 085 this.status = status; 086 this.reason = reason; 087 this.version = version; 088 this.entity = entity; 089 } 090 091 /** 092 * Adds a pair key / expression to the header. 093 * 094 * @param key 095 * The header key. 096 * @param expression 097 * The expression to evaluate. 098 * @return The current static response handler. 099 */ 100 public StaticResponseHandler addHeader(final String key, final Expression expression) { 101 headers.add(key, expression); 102 return this; 103 } 104 105 @Override 106 public void handle(Exchange exchange) throws HandlerException, IOException { 107 Response response = new Response(); 108 response.setStatus(this.status); 109 response.setReason(this.reason); 110 if (response.getReason() == null) { 111 // not explicit, derive from status 112 response.setReason(HttpUtil.getReason(response.getStatus())); 113 } 114 if (response.getReason() == null) { 115 // couldn't derive from status; say something 116 response.setReason("Uncertain"); 117 } 118 if (this.version != null) { // default in Message class 119 response.setVersion(this.version); 120 } 121 for (String key : this.headers.keySet()) { 122 for (Expression expression : this.headers.get(key)) { 123 String eval = expression.eval(exchange, String.class); 124 if (eval != null) { 125 response.getHeaders().add(key, eval); 126 } 127 } 128 } 129 if (entity != null) { 130 // use content-type charset (or default) 131 response.setEntity(entity.eval(exchange, String.class)); 132 } 133 // finally replace response in the exchange 134 closeSilently(exchange.response); 135 exchange.response = response; 136 } 137 138 /** 139 * Creates and initializes a static response handler in a heap environment. 140 */ 141 public static class Heaplet extends GenericHeaplet { 142 @Override 143 public Object create() throws HeapException { 144 final int status = config.get("status").required().asInteger(); 145 final String reason = config.get("reason").asString(); 146 final String version = config.get("version").asString(); 147 final JsonValue headers = config.get("headers").expect(Map.class); 148 final Expression entity = asExpression(config.get("entity")); 149 final StaticResponseHandler handler = new StaticResponseHandler(status, reason, version, entity); 150 if (headers != null) { 151 for (String key : headers.keys()) { 152 for (JsonValue value : headers.get(key).expect(List.class)) { 153 handler.addHeader(key, asExpression(value.required())); 154 } 155 } 156 } 157 return handler; 158 } 159 } 160}