blob: d98bff4af6db7804a83ca02fc6e3223c7bd6f4ba [file] [log] [blame]
/*******************************************************************************
* 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.sightly.impl.engine.extension;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Map;
import javax.script.Bindings;
import javax.servlet.Servlet;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.scripting.SlingScriptHelper;
import org.apache.sling.api.servlets.ServletResolver;
import org.apache.sling.scripting.sightly.SightlyException;
import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
import org.apache.sling.scripting.sightly.impl.utils.BindingsUtils;
import org.apache.sling.scripting.sightly.render.RenderContext;
import org.apache.sling.scripting.sightly.render.RuntimeObjectModel;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Runtime support for including resources in a HTL script through {@code data-sly-include}.
*/
@Component(
service = RuntimeExtension.class,
property = {
RuntimeExtension.NAME + "=" + RuntimeExtension.INCLUDE
}
)
public class IncludeRuntimeExtension implements RuntimeExtension {
private static final Logger LOG = LoggerFactory.getLogger(IncludeRuntimeExtension.class);
private static final String OPTION_FILE = "file";
private static final String OPTION_PREPEND_PATH = "prependPath";
private static final String OPTION_APPEND_PATH = "appendPath";
private static final String OPTION_REQUEST_ATTRIBUTES = "requestAttributes";
@Override
public Object call(final RenderContext renderContext, Object... arguments) {
ExtensionUtils.checkArgumentCount(RuntimeExtension.INCLUDE, arguments, 2);
RuntimeObjectModel runtimeObjectModel = renderContext.getObjectModel();
String originalPath = runtimeObjectModel.toString(arguments[0]);
Map options = (Map) arguments[1];
String path = buildPath(originalPath, options);
StringWriter output = new StringWriter();
final Bindings bindings = renderContext.getBindings();
SlingHttpServletRequest request = BindingsUtils.getRequest(bindings);
Map originalAttributes = ExtensionUtils.setRequestAttributes(request, (Map)options.remove(OPTION_REQUEST_ATTRIBUTES));
includeScript(bindings, path, new PrintWriter(output));
ExtensionUtils.setRequestAttributes(request, originalAttributes);
return output.toString();
}
private String buildPath(String path, Map options) {
if (StringUtils.isEmpty(path)) {
path = (String) options.get(OPTION_FILE);
}
if (StringUtils.isEmpty(path)) {
return null;
}
String prependPath = (String) options.get(OPTION_PREPEND_PATH);
if (prependPath == null) {
prependPath = StringUtils.EMPTY;
}
if (StringUtils.isNotEmpty(prependPath)) {
if (!prependPath.endsWith("/") && !path.startsWith("/")) {
prependPath += "/";
}
}
String appendPath = (String) options.get(OPTION_APPEND_PATH);
if (appendPath == null) {
appendPath = StringUtils.EMPTY;
}
if (StringUtils.isNotEmpty(appendPath)) {
if (!appendPath.startsWith("/") && !path.endsWith("/")) {
appendPath = "/" + appendPath;
}
}
return prependPath + path + appendPath;
}
private void includeScript(final Bindings bindings, String script, PrintWriter out) {
if (StringUtils.isEmpty(script)) {
throw new SightlyException("Path for data-sly-include is empty");
} else {
LOG.debug("Attempting to include script {}.", script);
SlingScriptHelper slingScriptHelper = BindingsUtils.getHelper(bindings);
ServletResolver servletResolver = slingScriptHelper.getService(ServletResolver.class);
if (servletResolver != null) {
SlingHttpServletRequest request = BindingsUtils.getRequest(bindings);
Servlet servlet = servletResolver.resolveServlet(request.getResource(), script);
if (servlet != null) {
try {
SlingHttpServletResponse response = BindingsUtils.getResponse(bindings);
PrintWriterResponseWrapper resWrapper = new PrintWriterResponseWrapper(out, response);
servlet.service(request, resWrapper);
} catch (Exception e) {
throw new SightlyException("Failed to include script " + script, e);
}
} else {
throw new SightlyException("Failed to locate script " + script);
}
} else {
throw new SightlyException("Sling ServletResolver service is unavailable, failed to include " + script);
}
}
}
}