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.rest.server.converter;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021import org.apache.juneau.http.response.*;
022import org.apache.juneau.marshall.*;
023import org.apache.juneau.marshall.objecttools.*;
024import org.apache.juneau.marshall.parser.*;
025import org.apache.juneau.rest.server.*;
026
027/**
028 * Converter for enabling path-addressing support on response objects returned by a <c>@RestOp</c>-annotated method.
029 *
030 * <p>
031 * When enabled, objects in a POJO tree returned by the REST method can be addressed through additional URL path
032 * information.
033 *
034 * <p class='bjava'>
035 *    <jc>// Resource method on resource "http://localhost:8080/sample/addressBook"</jc>
036 *    <ja>@RestOp</ja>(method=<jsf>GET</jsf>, converters=Traversable.<jk>class</jk>)
037 *    <jk>public void</jk> doGet(RestRequest <jv>req</jv>, RestResponse <jv>res</jv>) {
038 *       <jk>return new</jk> AddressBook();
039 *    }
040 * </p>
041 *
042 * <h5 class='section'>See Also:</h5><ul>
043 *    <li class='ja'>{@link RestOp#converters()} - Registering converters with REST resources.
044 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Converters">Converters</a>
045 * </ul>
046 */
047public class Traversable implements RestConverter {
048
049   @Override /* Overridden from RestConverter */
050   public Object convert(RestRequest req, Object o) throws BasicHttpException, InternalServerError {
051      if (o == null)
052         return null;
053
054      String pathRemainder = req.getPathRemainder().orElse(null);
055
056      if (nn(pathRemainder)) {
057         try {
058            MarshallingSession bs = req.getMarshallingSession();
059            var swap = bs.getClassMetaForObject(o).getSwap(bs);
060            if (nn(swap))
061               o = swap.swap(bs, o);
062            ReaderParser rp = req.getContent().getParserMatch().map(ParserMatch::getParser).filter(ReaderParser.class::isInstance).map(ReaderParser.class::cast).orElse(null);
063            var or = PathTraversal.create(o, rp);
064            o = or.get(pathRemainder);
065         } catch (PathTraversalException e) {
066            throw new BasicHttpException(e.getStatus(), null, e);
067         } catch (Exception t) {
068            throw new InternalServerError(t);
069         }
070      }
071
072      return o;
073   }
074}