/* * Copyright 2011 <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ocpsoft.rewrite.showcase.rest; import java.io.IOException; import java.io.PrintWriter; import java.util.Arrays; import java.util.Set; import javax.inject.Inject; import javax.servlet.ServletContext; import org.ocpsoft.rewrite.bind.Evaluation; import org.ocpsoft.rewrite.config.Configuration; import org.ocpsoft.rewrite.config.ConfigurationBuilder; import org.ocpsoft.rewrite.context.EvaluationContext; import org.ocpsoft.rewrite.param.ParameterStore; import org.ocpsoft.rewrite.param.Parameterized; import org.ocpsoft.rewrite.param.RegexParameterizedPatternBuilder; import org.ocpsoft.rewrite.servlet.config.HttpConfigurationProvider; import org.ocpsoft.rewrite.servlet.config.HttpOperation; import org.ocpsoft.rewrite.servlet.config.Method; import org.ocpsoft.rewrite.servlet.config.Path; import org.ocpsoft.rewrite.servlet.config.Response; import org.ocpsoft.rewrite.servlet.config.SendStatus; import org.ocpsoft.rewrite.servlet.http.event.HttpInboundServletRewrite; import org.ocpsoft.rewrite.servlet.http.event.HttpServletRewrite; /** * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a> * */ public class RestRewriteConfiguration extends HttpConfigurationProvider { private final class PostOperation extends HttpOperation implements Parameterized { @Override public void performHttp(final HttpServletRewrite event, final EvaluationContext context) { try { Product product = XMLUtil.streamToObject(Product.class, event.getRequest().getInputStream()); product = products.add(product); /** * Just for fun, set a response header containing the URL to the newly created Product. */ String location = new RegexParameterizedPatternBuilder(event.getContextPath() + "/store/product/{pid}").build(Arrays.<Object> asList(product.getId())); Response.addHeader("Location", location).perform(event, context); event.getResponse().setContentType("text/html"); ((HttpInboundServletRewrite) event).sendStatusCode(200); } catch (Exception e) { throw new RuntimeException(e); } } @Override public Set<String> getRequiredParameterNames() { return null; } @Override public void setParameterStore(ParameterStore store) { } } @Inject private ProductRegistry products; @Inject private ProductConverter productConverter; @Inject private ProductValidator productValidator; @Override public Configuration getConfiguration(final ServletContext context) { return ConfigurationBuilder .begin() .addRule() /** * Define the inbound conditions and conversion mechanisms to be used when handling inbound requests. */ .when(Method.isGet() .and(Path.matches("/store/product/{pid}"))) .perform(new HttpOperation() { @Override public void performHttp(final HttpServletRewrite event, final EvaluationContext context) { /** * Extract the stored {pid} from our Path and load the Product. This is an example of how we can * use a converter to directly bind and store the object we want into a binding. {@link Evaluation} * is an low-level construct, and binds array values that must be dereferenced. If using other * bindings such as {@link El}, the value will be bound directly to the type of the referenced * property type, and this array downcast is not necessary. */ ParameterStore store = (ParameterStore) context.get(ParameterStore.class); Product product = (Product) Evaluation.property("pid").retrieveConverted(event, context, store.get("pid")); /** * Marshal the Product into XML using JAXB. This has been extracted into a utility class. */ try { XMLUtil.streamFromObject(Product.class, product, event.getResponse() .getOutputStream()); } catch (IOException e) { throw new RuntimeException(e); } /** * Set the content type and status code of the response, this again could be extracted into a REST * utility class. */ event.getResponse().setContentType("application/xml"); ((HttpInboundServletRewrite) event).sendStatusCode(200); } }).where("pid").matches("\\d+") .constrainedBy(new IntegerConstraint()) .convertedBy(productConverter) .validatedBy(productValidator) .addRule() .when(Path.matches("/store/products").and(Method.isGet())) .perform(new HttpOperation() { @Override public void performHttp(final HttpServletRewrite event, final EvaluationContext context) { try { XMLUtil.streamFromObject(ProductRegistry.class, products, event.getResponse().getOutputStream()); event.getResponse().setContentType("application/xml"); ((HttpInboundServletRewrite) event).sendStatusCode(200); } catch (Exception e) { throw new RuntimeException(e); } } }) .addRule() .when(Path.matches("/store/products").and(Method.isPost())) .perform(new PostOperation()) .addRule().when(Path.matches("/")).perform(new HttpOperation() { @Override public void performHttp(final HttpServletRewrite event, final EvaluationContext context) { try { PrintWriter writer = event.getResponse().getWriter(); writer.write("<html>" + "<body>" + "<h1>Rewrite Rest Demo</h1>" + "Sorry for the boring page, there are no HTML pages in this demo! Try some of the following operations:" + "" + "<ul>" + "<li>GET <a href=\"" + event.getContextPath() + "/store/product/0\">/store/product/0</a></li>" + "<li>GET <a href=\"" + event.getContextPath() + "/store/products\">/store/products</a></li>" + "<li>POST " + event.getContextPath() + "/store/products - This requires a rest client, or you can use `curl`<br/>" + "curl --data \"<product><name>James</name><description>yay</description><price>12.9</price></product>\" http://localhost:8080/rewrite-showcase-rest/store/products</li>" + "</ul>" + "</body></html>"); SendStatus.code(200).perform(event, context); } catch (IOException e) { throw new RuntimeException(); } } }); } @Override public int priority() { return 0; } }