| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.apache.sling.scripting.core; |
| |
| import java.io.IOException; |
| import java.lang.reflect.Array; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import javax.servlet.RequestDispatcher; |
| import javax.servlet.ServletException; |
| |
| import org.apache.sling.api.SlingHttpServletRequest; |
| import org.apache.sling.api.SlingHttpServletResponse; |
| import org.apache.sling.api.SlingIOException; |
| import org.apache.sling.api.SlingServletException; |
| import org.apache.sling.api.request.RequestDispatcherOptions; |
| import org.apache.sling.api.resource.Resource; |
| import org.apache.sling.api.scripting.InvalidServiceFilterSyntaxException; |
| import org.apache.sling.api.scripting.SlingScript; |
| import org.apache.sling.api.scripting.SlingScriptHelper; |
| import org.apache.sling.api.wrappers.SlingHttpServletRequestWrapper; |
| import org.apache.sling.api.wrappers.SlingHttpServletResponseWrapper; |
| import org.apache.sling.scripting.core.impl.helper.OnDemandReaderRequest; |
| import org.apache.sling.scripting.core.impl.helper.OnDemandWriterResponse; |
| import org.jetbrains.annotations.NotNull; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.InvalidSyntaxException; |
| import org.osgi.framework.ServiceReference; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * Simple script helper providing access to the (wrapped) response, the |
| * on-demand writer and a simple API for request inclusion. Instances of this |
| * class are made available to the scripts as the global <code>sling</code> |
| * variable. |
| * |
| * Client code using this object should take care to call {@link #cleanup()} |
| * when the object is not used anymore! |
| */ |
| public class ScriptHelper implements SlingScriptHelper { |
| |
| /** The corresponding script. */ |
| private final SlingScript script; |
| |
| /** The current request or <code>null</code>. */ |
| private final SlingHttpServletRequest request; |
| |
| /** The current response or <code>null</code>. */ |
| private final SlingHttpServletResponse response; |
| |
| /** The bundle context. */ |
| protected final BundleContext bundleContext; |
| |
| /** |
| * The list of references - we don't need to synchronize this as we are |
| * running in one single request. |
| */ |
| protected List<ServiceReference> references; |
| |
| /** A map of found services. */ |
| protected Map<String, Object> services; |
| |
| public ScriptHelper(final BundleContext ctx, final SlingScript script) { |
| if (ctx == null ) { |
| throw new IllegalArgumentException("Bundle context must not be null."); |
| } |
| this.request = null; |
| this.response = null; |
| this.script = script; |
| this.bundleContext = ctx; |
| } |
| |
| public ScriptHelper(final BundleContext ctx, |
| final SlingScript script, |
| final SlingHttpServletRequest request, |
| final SlingHttpServletResponse response) { |
| if (ctx == null ) { |
| throw new IllegalArgumentException("Bundle context must not be null."); |
| } |
| this.script = script; |
| this.request = wrapIfNeeded(request); |
| this.response = wrapIfNeeded(response); |
| this.bundleContext = ctx; |
| } |
| |
| /** |
| * @see org.apache.sling.api.scripting.SlingScriptHelper#getScript() |
| */ |
| public SlingScript getScript() { |
| return script; |
| } |
| |
| /** |
| * @see org.apache.sling.api.scripting.SlingScriptHelper#getRequest() |
| */ |
| public SlingHttpServletRequest getRequest() { |
| return request; |
| } |
| |
| /** |
| * @see org.apache.sling.api.scripting.SlingScriptHelper#getResponse() |
| */ |
| public SlingHttpServletResponse getResponse() { |
| return response; |
| } |
| |
| /** |
| * @see org.apache.sling.api.scripting.SlingScriptHelper#include(java.lang.String) |
| */ |
| public void include(String path) { |
| include(path, (RequestDispatcherOptions) null); |
| } |
| |
| /** |
| * @see org.apache.sling.api.scripting.SlingScriptHelper#include(java.lang.String, java.lang.String) |
| */ |
| public void include(String path, String options) { |
| include(path, new RequestDispatcherOptions(options)); |
| } |
| |
| /** |
| * @see org.apache.sling.api.scripting.SlingScriptHelper#include(java.lang.String, org.apache.sling.api.request.RequestDispatcherOptions) |
| */ |
| public void include(String path, RequestDispatcherOptions options) { |
| final RequestDispatcher dispatcher = getRequest().getRequestDispatcher( |
| path, options); |
| |
| if (dispatcher != null) { |
| try { |
| dispatcher.include(getRequest(), getResponse()); |
| } catch (IOException ioe) { |
| throw new SlingIOException(ioe); |
| } catch (ServletException se) { |
| throw new SlingServletException(se); |
| } |
| } |
| } |
| |
| /** |
| * @see org.apache.sling.api.scripting.SlingScriptHelper#forward(java.lang.String) |
| */ |
| public void forward(String path) { |
| forward(path, (RequestDispatcherOptions) null); |
| } |
| |
| /** |
| * @see org.apache.sling.api.scripting.SlingScriptHelper#forward(java.lang.String, java.lang.String) |
| */ |
| public void forward(String path, String options) { |
| forward(path, new RequestDispatcherOptions(options)); |
| } |
| |
| /** |
| * @see org.apache.sling.api.scripting.SlingScriptHelper#forward(java.lang.String, org.apache.sling.api.request.RequestDispatcherOptions) |
| */ |
| public void forward(String path, RequestDispatcherOptions options) { |
| final RequestDispatcher dispatcher = getRequest().getRequestDispatcher( |
| path, options); |
| |
| if (dispatcher != null) { |
| try { |
| dispatcher.forward(getRequest(), getResponse()); |
| } catch (IOException ioe) { |
| throw new SlingIOException(ioe); |
| } catch (ServletException se) { |
| throw new SlingServletException(se); |
| } |
| } |
| } |
| |
| /** |
| * @see org.apache.sling.api.scripting.SlingScriptHelper#dispose() |
| */ |
| @Deprecated |
| public void dispose() { |
| LoggerFactory.getLogger(this.getClass()).error("ScriptHelper#dispose has been called. This method is deprecated and should never be called by clients!"); |
| } |
| |
| /** |
| * @see org.apache.sling.api.scripting.SlingScriptHelper#getService(java.lang.Class) |
| */ |
| @SuppressWarnings("unchecked") |
| public <ServiceType> ServiceType getService(Class<ServiceType> type) { |
| ServiceType service = (this.services == null ? null : (ServiceType) this.services.get(type.getName())); |
| if (service == null) { |
| final ServiceReference ref = this.bundleContext.getServiceReference(type.getName()); |
| if (ref != null) { |
| service = (ServiceType) this.bundleContext.getService(ref); |
| if ( service != null ) { |
| if ( this.services == null ) { |
| this.services = new HashMap<String, Object>(); |
| } |
| if ( this.references == null ) { |
| this.references = new ArrayList<ServiceReference>(); |
| } |
| this.references.add(ref); |
| this.services.put(type.getName(), service); |
| } |
| } |
| } |
| return service; |
| } |
| |
| /** |
| * @see org.apache.sling.api.scripting.SlingScriptHelper#getServices(java.lang.Class, java.lang.String) |
| */ |
| @SuppressWarnings("unchecked") |
| public <ServiceType> ServiceType[] getServices( |
| Class<ServiceType> serviceType, String filter) |
| throws InvalidServiceFilterSyntaxException { |
| try { |
| final ServiceReference[] refs = this.bundleContext.getServiceReferences( |
| serviceType.getName(), filter); |
| ServiceType[] result = null; |
| if (refs != null) { |
| // sort by service ranking (lowest first) (see ServiceReference#compareTo(Object)) |
| List<ServiceReference> references = Arrays.asList(refs); |
| Collections.sort(references); |
| // get the highest ranking first |
| Collections.reverse(references); |
| |
| final List<ServiceType> objects = new ArrayList<ServiceType>(); |
| for (ServiceReference reference : references) { |
| final ServiceType service = (ServiceType) this.bundleContext.getService(reference); |
| if (service != null) { |
| if ( this.references == null ) { |
| this.references = new ArrayList<ServiceReference>(); |
| } |
| this.references.add(reference); |
| objects.add(service); |
| } |
| } |
| if (objects.size() > 0) { |
| ServiceType[] srv = (ServiceType[]) Array.newInstance(serviceType, objects.size()); |
| result = objects.toArray(srv); |
| } |
| } |
| return result; |
| } catch (InvalidSyntaxException ise) { |
| throw new InvalidServiceFilterSyntaxException(filter, |
| "Invalid filter syntax", ise); |
| } |
| } |
| |
| /** |
| * Clean up this instance. |
| */ |
| public void cleanup() { |
| if ( this.references != null ) { |
| final Iterator<ServiceReference> i = this.references.iterator(); |
| while (i.hasNext()) { |
| final ServiceReference ref = i.next(); |
| this.bundleContext.ungetService(ref); |
| } |
| this.references.clear(); |
| } |
| if ( this.services != null ) { |
| this.services.clear(); |
| } |
| } |
| |
| /** |
| * @see org.apache.sling.api.scripting.SlingScriptHelper#forward(org.apache.sling.api.resource.Resource) |
| */ |
| public void forward(Resource resource) { |
| forward(resource, (RequestDispatcherOptions) null); |
| } |
| |
| |
| /** |
| * @see org.apache.sling.api.scripting.SlingScriptHelper#forward(org.apache.sling.api.resource.Resource, java.lang.String) |
| */ |
| public void forward(Resource resource, String options) { |
| forward(resource, new RequestDispatcherOptions(options)); |
| } |
| |
| /** |
| * @see org.apache.sling.api.scripting.SlingScriptHelper#forward(org.apache.sling.api.resource.Resource, org.apache.sling.api.request.RequestDispatcherOptions) |
| */ |
| public void forward(Resource resource, RequestDispatcherOptions options) { |
| final RequestDispatcher dispatcher = getRequest().getRequestDispatcher( |
| resource, options); |
| |
| if (dispatcher != null) { |
| try { |
| dispatcher.forward(getRequest(), getResponse()); |
| } catch (IOException ioe) { |
| throw new SlingIOException(ioe); |
| } catch (ServletException se) { |
| throw new SlingServletException(se); |
| } |
| } |
| } |
| |
| /** |
| * @see org.apache.sling.api.scripting.SlingScriptHelper#forward(org.apache.sling.api.resource.Resource) |
| */ |
| public void include(Resource resource) { |
| include(resource, (RequestDispatcherOptions) null); |
| } |
| |
| /** |
| * @see org.apache.sling.api.scripting.SlingScriptHelper#include(org.apache.sling.api.resource.Resource, java.lang.String) |
| */ |
| public void include(Resource resource, String options) { |
| include(resource, new RequestDispatcherOptions(options)); |
| } |
| |
| /** |
| * @see org.apache.sling.api.scripting.SlingScriptHelper#include(org.apache.sling.api.resource.Resource, org.apache.sling.api.request.RequestDispatcherOptions) |
| */ |
| public void include(Resource resource, RequestDispatcherOptions options) { |
| final RequestDispatcher dispatcher = getRequest().getRequestDispatcher( |
| resource, options); |
| |
| if (dispatcher != null) { |
| try { |
| dispatcher.include(getRequest(), getResponse()); |
| } catch (IOException ioe) { |
| throw new SlingIOException(ioe); |
| } catch (ServletException se) { |
| throw new SlingServletException(se); |
| } |
| } |
| } |
| |
| private SlingHttpServletRequest wrapIfNeeded(@NotNull SlingHttpServletRequest request) { |
| SlingHttpServletRequest initialRequest = request; |
| while (request instanceof SlingHttpServletRequestWrapper) { |
| if (request instanceof OnDemandReaderRequest) { |
| return initialRequest; |
| } |
| request = ((SlingHttpServletRequestWrapper) request).getSlingRequest(); |
| } |
| return new OnDemandReaderRequest(initialRequest); |
| } |
| |
| private SlingHttpServletResponse wrapIfNeeded(@NotNull SlingHttpServletResponse response) { |
| SlingHttpServletResponse initialResponse = response; |
| while (response instanceof SlingHttpServletResponseWrapper) { |
| if (response instanceof OnDemandWriterResponse) { |
| return initialResponse; |
| } |
| response = ((SlingHttpServletResponseWrapper) response).getSlingResponse(); |
| } |
| return new OnDemandWriterResponse(initialResponse); |
| } |
| } |