blob: f4f44e28d9d326ba4ff67b7e4d59743790afe85a [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.bundle.tracker.internal;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.commons.compiler.source.JavaEscapeHelper;
import org.apache.sling.scripting.bundle.tracker.BundledRenderUnitCapability;
import org.apache.sling.scripting.bundle.tracker.ResourceType;
import org.apache.sling.scripting.bundle.tracker.TypeProvider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.osgi.framework.Bundle;
import org.osgi.service.component.annotations.Component;
@Component(
service = BundledScriptFinder.class
)
public class BundledScriptFinder {
private static final String NS_JAVAX_SCRIPT_CAPABILITY = "javax.script";
private static final String SLASH = "/";
private static final String DOT = ".";
Executable getScript(Set<TypeProvider> providers, Set<TypeProvider> allProviders) {
for (TypeProvider provider : providers) {
BundledRenderUnitCapability capability = provider.getBundledRenderUnitCapability();
for (String match : buildScriptMatches(capability.getResourceTypes(),
capability.getSelectors().toArray(new String[0]), capability.getMethod(), capability.getExtension())) {
String scriptExtension = capability.getScriptExtension();
String scriptEngineName = capability.getScriptEngineName();
if (StringUtils.isNotEmpty(scriptExtension) && StringUtils.isNotEmpty(scriptEngineName)) {
Executable executable = getExecutable(provider.getBundle(), match, scriptEngineName, scriptExtension, allProviders);
if (executable != null) {
return executable;
}
}
}
}
return null;
}
Executable getScript(@NotNull Bundle bundle, @NotNull String path, @NotNull String scriptEngineName,
@NotNull Set<TypeProvider> providers) {
String className = JavaEscapeHelper.makeJavaPackage(path);
try {
Class<?> clazz = bundle.loadClass(className);
return new PrecompiledScript(providers, bundle, path, clazz, scriptEngineName);
} catch (ClassNotFoundException ignored) {
URL bundledScriptURL = bundle.getEntry(NS_JAVAX_SCRIPT_CAPABILITY + (path.startsWith("/") ? "" : SLASH) + path);
if (bundledScriptURL != null) {
return new Script(providers, bundle, path, bundledScriptURL, scriptEngineName);
} // do nothing here
}
return null;
}
@Nullable
private Executable getExecutable(@NotNull Bundle bundle, @NotNull String match, @NotNull String scriptEngineName,
@NotNull String scriptExtension, @NotNull Set<TypeProvider> providers) {
String path = match + DOT + scriptExtension;
return getScript(bundle, path, scriptEngineName, providers);
}
private List<String> buildScriptMatches(Set<ResourceType> resourceTypes, String[] selectors, String method, String extension) {
List<String> matches = new ArrayList<>();
for (ResourceType resourceType : resourceTypes) {
if (selectors.length > 0) {
for (int i = selectors.length - 1; i >= 0; i--) {
String base =
resourceType.getType() +
(StringUtils.isNotEmpty(resourceType.getVersion()) ? SLASH + resourceType.getVersion() + SLASH :
SLASH) +
String.join(SLASH, Arrays.copyOf(selectors, i + 1));
if (StringUtils.isNotEmpty(extension)) {
if (StringUtils.isNotEmpty(method)) {
matches.add(base + DOT + extension + DOT + method);
}
matches.add(base + DOT + extension);
}
if (StringUtils.isNotEmpty(method)) {
matches.add(base + DOT + method);
}
matches.add(base);
}
}
String base = resourceType.getType() +
(StringUtils.isNotEmpty(resourceType.getVersion()) ? SLASH + resourceType.getVersion() : StringUtils.EMPTY);
if (StringUtils.isNotEmpty(extension)) {
if (StringUtils.isNotEmpty(method)) {
matches.add(base + SLASH + resourceType.getResourceLabel() + DOT + extension + DOT + method);
}
matches.add(base + SLASH + resourceType.getResourceLabel() + DOT + extension);
}
if (StringUtils.isNotEmpty(method)) {
matches.add(base + SLASH + resourceType.getResourceLabel() + DOT + method);
}
matches.add(base + SLASH + resourceType.getResourceLabel());
if (StringUtils.isNotEmpty(method)) {
matches.add(base + SLASH + method);
}
if (StringUtils.isNotEmpty(extension)) {
matches.add(base + SLASH + extension);
}
}
return Collections.unmodifiableList(matches);
}
}