diff --git a/gradle/defaults.gradle b/gradle/defaults.gradle index 0ce26d143c9..0ca1af1a60e 100644 --- a/gradle/defaults.gradle +++ b/gradle/defaults.gradle @@ -23,9 +23,6 @@ allprojects { // Repositories to fetch dependencies from. repositories { mavenCentral() - maven { - url "https://maven.restlet.com" - } } // Artifacts will have names after full gradle project path diff --git a/gradle/validation/owasp-dependency-check/exclusions.xml b/gradle/validation/owasp-dependency-check/exclusions.xml index 0a77b99d3b8..83fe6e6cd17 100644 --- a/gradle/validation/owasp-dependency-check/exclusions.xml +++ b/gradle/validation/owasp-dependency-check/exclusions.xml @@ -62,36 +62,6 @@ ^pkg:maven/com\.google\.guava/guava@.*$ CVE-2018-10237 - - - ^pkg:maven/org\.restlet\.jee/org\.restlet\.ext\.servlet@.*$ - cpe:/a:restlet:restlet_framework - - - - ^pkg:maven/org\.restlet\.jee/org\.restlet\.ext\.servlet@.*$ - cpe:/a:restlet:restlet - - - - ^pkg:maven/org\.restlet\.jee/org\.restlet@.*$ - CVE-2017-14868 - - - - ^pkg:maven/org\.restlet\.jee/org\.restlet@.*$ - CVE-2017-14949 - extraServlets = new TreeMap<>(); - final ServletHolder solrRestApi = new ServletHolder("SolrSchemaRestApi", - ServerServlet.class); - solrRestApi.setInitParameter("org.restlet.application", - SolrSchemaRestApi.class.getCanonicalName()); - solrRestApi.setInitParameter("storageIO", - ManagedResourceStorage.InMemoryStorageIO.class.getCanonicalName()); - extraServlets.put(solrRestApi, PARENT_ENDPOINT); - System.setProperty("managed.schema.mutable", "true"); - + final SortedMap extraServlets = new TreeMap<>(); return extraServlets; } diff --git a/solr/core/build.gradle b/solr/core/build.gradle index 8c7bcc9008c..cfbd6d6a567 100644 --- a/solr/core/build.gradle +++ b/solr/core/build.gradle @@ -95,9 +95,7 @@ dependencies { implementation 'org.codehaus.janino:commons-compiler' implementation 'org.codehaus.janino:janino' - api 'org.restlet.jee:org.restlet' implementation 'org.rrd4j:rrd4j' - implementation 'org.restlet.jee:org.restlet.ext.servlet' implementation ('org.apache.calcite.avatica:avatica-core') { transitive = false } implementation ('org.apache.calcite:calcite-core') { transitive = false } diff --git a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java index 606bab51536..5a8f9d29665 100644 --- a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java @@ -39,6 +39,7 @@ import org.apache.solr.pkg.PackageListeningClassLoader; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.request.SolrRequestHandler; import org.apache.solr.response.SolrQueryResponse; +import org.apache.solr.rest.RestManager; import org.apache.solr.schema.IndexSchema; import org.apache.solr.schema.ManagedIndexSchema; import org.apache.solr.schema.SchemaManager; @@ -60,6 +61,7 @@ import static org.apache.solr.schema.IndexSchema.SchemaProps.Handler.FIELD_TYPES public class SchemaHandler extends RequestHandlerBase implements SolrCoreAware, PermissionNameProvider { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private boolean isImmutableConfigSet = false; + private SolrRequestHandler managedResourceRequestHandler; private static final Map level2; @@ -106,6 +108,8 @@ public class SchemaHandler extends RequestHandlerBase implements SolrCoreAware, switch (ctx.getHttpMethod()) { case "GET": return PermissionNameProvider.Name.SCHEMA_READ_PERM; + case "PUT": + case "DELETE": case "POST": return PermissionNameProvider.Name.SCHEMA_EDIT_PERM; default: @@ -257,6 +261,8 @@ public class SchemaHandler extends RequestHandlerBase implements SolrCoreAware, String prefix = parts.get(0); if(subPaths.contains(prefix)) return this; + if(managedResourceRequestHandler != null) return managedResourceRequestHandler; + return null; } @@ -273,6 +279,7 @@ public class SchemaHandler extends RequestHandlerBase implements SolrCoreAware, @Override public void inform(SolrCore core) { isImmutableConfigSet = SolrConfigHandler.getImmutable(core); + this.managedResourceRequestHandler = new ManagedResourceRequestHandler(core.getRestManager()); } @Override @@ -290,4 +297,36 @@ public class SchemaHandler extends RequestHandlerBase implements SolrCoreAware, public Boolean registerV2() { return Boolean.TRUE; } + + private class ManagedResourceRequestHandler extends RequestHandlerBase implements PermissionNameProvider { + + + private final RestManager restManager; + + private ManagedResourceRequestHandler(RestManager restManager) { + this.restManager = restManager; + } + + @Override + public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) { + RestManager.ManagedEndpoint me = new RestManager.ManagedEndpoint(restManager); + me.doInit(req, rsp); + me.delegateRequestToManagedResource(); + } + + @Override + public Name getPermissionName(AuthorizationContext ctx) { + return SchemaHandler.this.getPermissionName(ctx); + } + + @Override + public String getName() { + return null; + } + + @Override + public String getDescription() { + return null; + } + } } diff --git a/solr/core/src/java/org/apache/solr/rest/BaseSolrResource.java b/solr/core/src/java/org/apache/solr/rest/BaseSolrResource.java index 01db581dc67..f07bb271bfe 100644 --- a/solr/core/src/java/org/apache/solr/rest/BaseSolrResource.java +++ b/solr/core/src/java/org/apache/solr/rest/BaseSolrResource.java @@ -15,37 +15,28 @@ * limitations under the License. */ package org.apache.solr.rest; -import java.io.IOException; -import java.io.OutputStream; + import java.io.UnsupportedEncodingException; import java.net.URLDecoder; +import org.apache.solr.common.SolrException; import org.apache.solr.common.params.CommonParams; -import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.core.SolrCore; import org.apache.solr.request.SolrQueryRequest; -import org.apache.solr.request.SolrRequestInfo; import org.apache.solr.response.QueryResponseWriter; -import org.apache.solr.response.QueryResponseWriterUtil; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.schema.IndexSchema; import org.apache.solr.servlet.ResponseUtils; -import org.restlet.data.MediaType; -import org.restlet.data.Method; -import org.restlet.data.Status; -import org.restlet.representation.OutputRepresentation; -import org.restlet.resource.ResourceException; -import org.restlet.resource.ServerResource; import org.slf4j.Logger; - import static org.apache.solr.common.params.CommonParams.JSON; /** - * Base class of all Solr Restlet server resource classes. + * Base class for delegating REST-oriented requests to ManagedResources. ManagedResources are heavy-weight and + * should not be created for every request, so this class serves as a gateway between a REST call and the resource. */ -public abstract class BaseSolrResource extends ServerResource { +public abstract class BaseSolrResource { protected static final String SHOW_DEFAULTS = "showDefaults"; public static final String UPDATE_TIMEOUT_SECS = "updateTimeoutSecs"; @@ -56,6 +47,7 @@ public abstract class BaseSolrResource extends ServerResource { private QueryResponseWriter responseWriter; private String contentType; private int updateTimeoutSecs = -1; + private int statusCode = -1; public SolrCore getSolrCore() { return solrCore; } public IndexSchema getSchema() { return schema; } @@ -73,92 +65,33 @@ public abstract class BaseSolrResource extends ServerResource { * from the SolrRequestInfo thread local, then gets the SolrCore * and IndexSchema and sets up the response. * writer. - *

- * If an error occurs during initialization, setExisting(false) is - * called and an error status code and message is set; in this case, - * Restlet will not continue servicing the request (by calling the - * method annotated to associate it with GET, etc., but rather will - * send an error response. */ - @Override - public void doInit() throws ResourceException { - super.doInit(); - setNegotiated(false); // Turn off content negotiation for now - if (isExisting()) { - try { - SolrRequestInfo solrRequestInfo = SolrRequestInfo.getRequestInfo(); - if (null == solrRequestInfo) { - final String message = "No handler or core found in " + getRequest().getOriginalRef().getPath(); - doError(Status.CLIENT_ERROR_BAD_REQUEST, message); - setExisting(false); - } else { - solrRequest = solrRequestInfo.getReq(); - if (null == solrRequest) { - final String message = "No handler or core found in " + getRequest().getOriginalRef().getPath(); - doError(Status.CLIENT_ERROR_BAD_REQUEST, message); - setExisting(false); - } else { - solrResponse = solrRequestInfo.getRsp(); - solrCore = solrRequest.getCore(); - schema = solrRequest.getSchema(); - String responseWriterName = solrRequest.getParams().get(CommonParams.WT); - if (null == responseWriterName) { - responseWriterName = JSON; // Default to json writer - } - String indent = solrRequest.getParams().get("indent"); - if (null == indent || ! ("off".equals(indent) || "false".equals(indent))) { - // indent by default - ModifiableSolrParams newParams = new ModifiableSolrParams(solrRequest.getParams()); - newParams.remove(indent); - newParams.add("indent", "on"); - solrRequest.setParams(newParams); - } - responseWriter = solrCore.getQueryResponseWriter(responseWriterName); - contentType = responseWriter.getContentType(solrRequest, solrResponse); - final String path = getRequest().getRootRef().getPath(); - if ( ! RestManager.SCHEMA_BASE_PATH.equals(path)) { - // don't set webapp property on the request when context and core/collection are excluded - final int cutoffPoint = path.indexOf("/", 1); - final String firstPathElement = -1 == cutoffPoint ? path : path.substring(0, cutoffPoint); - solrRequest.getContext().put("webapp", firstPathElement); // Context path - } - SolrCore.preDecorateResponse(solrRequest, solrResponse); - - // client application can set a timeout for update requests - String updateTimeoutSecsParam = getSolrRequest().getParams().get(UPDATE_TIMEOUT_SECS); - if (updateTimeoutSecsParam != null) - updateTimeoutSecs = Integer.parseInt(updateTimeoutSecsParam); - } - } - } catch (Throwable t) { - if (t instanceof OutOfMemoryError) { - throw (OutOfMemoryError) t; - } - setExisting(false); - throw new ResourceException(t); + public void doInit(SolrQueryRequest solrRequest, SolrQueryResponse solrResponse) { + try { + this.solrRequest = solrRequest; + this.solrResponse = solrResponse; + solrCore = solrRequest.getCore(); + schema = solrRequest.getSchema(); + String responseWriterName = solrRequest.getParams().get(CommonParams.WT, JSON); + responseWriter = solrCore.getQueryResponseWriter(responseWriterName); + contentType = responseWriter.getContentType(solrRequest, solrResponse); + final String path = solrRequest.getPath(); + if ( ! RestManager.SCHEMA_BASE_PATH.equals(path)) { + // don't set webapp property on the request when context and core/collection are excluded + final int cutoffPoint = path.indexOf("/", 1); + final String firstPathElement = -1 == cutoffPoint ? path : path.substring(0, cutoffPoint); + solrRequest.getContext().put("webapp", firstPathElement); // Context path } - } - } - /** - * This class serves as an adapter between Restlet and Solr's response writers. - */ - public class SolrOutputRepresentation extends OutputRepresentation { - - public SolrOutputRepresentation() { - // No normalization, in case of a custom media type - super(MediaType.valueOf(contentType)); - // TODO: For now, don't send the Vary: header, but revisit if/when content negotiation is added - getDimensions().clear(); - } - - - /** Called by Restlet to get the response body */ - @Override - public void write(OutputStream outputStream) throws IOException { - if (getRequest().getMethod() != Method.HEAD) { - QueryResponseWriterUtil.writeQueryResponse(outputStream, responseWriter, solrRequest, solrResponse, contentType); + // client application can set a timeout for update requests + String updateTimeoutSecsParam = solrRequest.getParams().get(UPDATE_TIMEOUT_SECS); + if (updateTimeoutSecsParam != null) + updateTimeoutSecs = Integer.parseInt(updateTimeoutSecsParam); + } catch (Throwable t) { + if (t instanceof OutOfMemoryError) { + throw (OutOfMemoryError) t; } + throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, t); } } @@ -169,9 +102,7 @@ public abstract class BaseSolrResource extends ServerResource { protected void handlePostExecution(Logger log) { handleException(log); - - // TODO: should status=0 (success?) be left as-is in the response header? - SolrCore.postDecorateResponse(null, solrRequest, solrResponse); + addDeprecatedWarning(); if (log.isInfoEnabled() && solrResponse.getToLog().size() > 0) { @@ -181,7 +112,6 @@ public abstract class BaseSolrResource extends ServerResource { protected void addDeprecatedWarning(){ solrResponse.add("warn","This API is deprecated"); - } /** @@ -197,8 +127,7 @@ public abstract class BaseSolrResource extends ServerResource { if (null != exception) { @SuppressWarnings({"rawtypes"}) NamedList info = new SimpleOrderedMap(); - int code = ResponseUtils.getErrorInfo(exception, info, log); - setStatus(Status.valueOf(code)); + this.statusCode = ResponseUtils.getErrorInfo(exception, info, log); getSolrResponse().add("error", info); String message = (String)info.get("msg"); if (null != message && ! message.trim().isEmpty()) { diff --git a/solr/core/src/java/org/apache/solr/rest/DELETEable.java b/solr/core/src/java/org/apache/solr/rest/DELETEable.java deleted file mode 100644 index 591f35ca866..00000000000 --- a/solr/core/src/java/org/apache/solr/rest/DELETEable.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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.solr.rest; - -import org.restlet.representation.Representation; -import org.restlet.resource.Delete; - -/** Marker interface for resource classes that handle DELETE requests. */ -public interface DELETEable { - @Delete - public Representation delete(); -} diff --git a/solr/core/src/java/org/apache/solr/rest/GETable.java b/solr/core/src/java/org/apache/solr/rest/GETable.java deleted file mode 100644 index 131ffe9ac34..00000000000 --- a/solr/core/src/java/org/apache/solr/rest/GETable.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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.solr.rest; - -import org.restlet.representation.Representation; -import org.restlet.resource.Get; - -/** Marker interface for resource classes that handle GET requests. */ -public interface GETable { - @Get - public Representation get(); -} diff --git a/solr/core/src/java/org/apache/solr/rest/ManagedResource.java b/solr/core/src/java/org/apache/solr/rest/ManagedResource.java index f9da549cd16..c6e7adfea1d 100644 --- a/solr/core/src/java/org/apache/solr/rest/ManagedResource.java +++ b/solr/core/src/java/org/apache/solr/rest/ManagedResource.java @@ -31,9 +31,6 @@ import org.apache.solr.common.SolrException.ErrorCode; import org.apache.solr.common.util.NamedList; import org.apache.solr.core.SolrResourceLoader; import org.apache.solr.rest.ManagedResourceStorage.StorageIO; -import org.restlet.data.Status; -import org.restlet.representation.Representation; -import org.restlet.resource.ResourceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -154,7 +151,7 @@ public abstract class ManagedResource { } /** - * Called from {@link #doPut(BaseSolrResource,Representation,Object)} + * Called from {@link #doPut(BaseSolrResource,Object)} * to update this resource's init args using the given updatedArgs */ @SuppressWarnings("unchecked") @@ -277,7 +274,7 @@ public abstract class ManagedResource { "Failed to store data for %s due to: %s", resourceId, storeErr.toString()); log.error(errMsg, storeErr); - throw new ResourceException(Status.SERVER_ERROR_INTERNAL, errMsg, storeErr); + throw new SolrException(ErrorCode.SERVER_ERROR, errMsg, storeErr); } } @@ -352,18 +349,18 @@ public abstract class ManagedResource { } /** - * Just calls {@link #doPut(BaseSolrResource,Representation,Object)}; + * Just calls {@link #doPut(BaseSolrResource,Object)}; * override to change the behavior of POST handling. */ - public void doPost(BaseSolrResource endpoint, Representation entity, Object json) { - doPut(endpoint, entity, json); + public void doPost(BaseSolrResource endpoint, Object json) { + doPut(endpoint, json); } /** * Applies changes to initArgs or managed data. */ @SuppressWarnings("unchecked") - public synchronized void doPut(BaseSolrResource endpoint, Representation entity, Object json) { + public synchronized void doPut(BaseSolrResource endpoint, Object json) { if (log.isInfoEnabled()) { log.info("Processing update to {}: {} is a {}", getResourceId(), json, json.getClass().getName()); @@ -392,7 +389,7 @@ public abstract class ManagedResource { } else if (json instanceof List) { managedData = json; } else { - throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, + throw new SolrException(ErrorCode.BAD_REQUEST, "Unsupported update format "+json.getClass().getName()); } @@ -425,15 +422,13 @@ public abstract class ManagedResource { protected abstract Object applyUpdatesToManagedData(Object updates); /** - * Called by {@link RestManager.ManagedEndpoint#delete()} - * to delete a named part (the given childId) of the + * Called to delete a named part (the given childId) of the * resource at the given endpoint */ public abstract void doDeleteChild(BaseSolrResource endpoint, String childId); /** - * Called by {@link RestManager.ManagedEndpoint#get()} - * to retrieve a named part (the given childId) of the + * Called to retrieve a named part (the given childId) of the * resource at the given endpoint */ public abstract void doGet(BaseSolrResource endpoint, String childId); diff --git a/solr/core/src/java/org/apache/solr/rest/ManagedResourceStorage.java b/solr/core/src/java/org/apache/solr/rest/ManagedResourceStorage.java index 52ad8307316..e9102a299da 100644 --- a/solr/core/src/java/org/apache/solr/rest/ManagedResourceStorage.java +++ b/solr/core/src/java/org/apache/solr/rest/ManagedResourceStorage.java @@ -44,8 +44,6 @@ import org.apache.solr.common.cloud.SolrZkClient; import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.Utils; import org.apache.solr.core.SolrResourceLoader; -import org.restlet.data.Status; -import org.restlet.resource.ResourceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -302,7 +300,7 @@ public abstract class ManagedResourceStorage { if (e instanceof RuntimeException) { throw (RuntimeException)e; } else { - throw new ResourceException(Status.SERVER_ERROR_INTERNAL, + throw new SolrException(ErrorCode.SERVER_ERROR, "Failed to save data to ZooKeeper znode: "+znodePath+" due to: "+e, e); } } diff --git a/solr/core/src/java/org/apache/solr/rest/POSTable.java b/solr/core/src/java/org/apache/solr/rest/POSTable.java deleted file mode 100644 index 5b7fd4e340b..00000000000 --- a/solr/core/src/java/org/apache/solr/rest/POSTable.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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.solr.rest; - -import org.restlet.representation.Representation; -import org.restlet.resource.Post; - -/** Marker interface for resource classes that handle POST requests. */ -public interface POSTable { - @Post - public Representation post(Representation representation); -} diff --git a/solr/core/src/java/org/apache/solr/rest/PUTable.java b/solr/core/src/java/org/apache/solr/rest/PUTable.java deleted file mode 100644 index e8b27b4632b..00000000000 --- a/solr/core/src/java/org/apache/solr/rest/PUTable.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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.solr.rest; - -import org.restlet.representation.Representation; -import org.restlet.resource.Put; - -/** Marker interface for resource classes that handle PUT requests. */ -public interface PUTable { - @Put - public Representation put(Representation entity); -} diff --git a/solr/core/src/java/org/apache/solr/rest/RestManager.java b/solr/core/src/java/org/apache/solr/rest/RestManager.java index addee77bf91..ea1d3c08072 100644 --- a/solr/core/src/java/org/apache/solr/rest/RestManager.java +++ b/solr/core/src/java/org/apache/solr/rest/RestManager.java @@ -18,13 +18,17 @@ package org.apache.solr.rest; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.Reader; +import java.io.UnsupportedEncodingException; import java.lang.invoke.MethodHandles; import java.lang.reflect.Constructor; +import java.net.URLDecoder; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; @@ -36,22 +40,15 @@ import java.util.regex.Pattern; import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException.ErrorCode; +import org.apache.solr.common.util.ContentStream; import org.apache.solr.common.util.NamedList; import org.apache.solr.core.SolrResourceLoader; import org.apache.solr.request.SolrQueryRequest; -import org.apache.solr.request.SolrRequestInfo; +import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.rest.ManagedResourceStorage.StorageIO; -import org.restlet.Request; -import org.restlet.data.MediaType; -import org.restlet.data.Method; -import org.restlet.data.Status; -import org.restlet.representation.Representation; -import org.restlet.resource.ResourceException; -import org.restlet.routing.Router; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import static org.apache.solr.common.util.Utils.fromJSONString; +import static org.apache.solr.common.util.Utils.fromJSON; /** * Supports runtime mapping of REST API endpoints to ManagedResource @@ -122,11 +119,6 @@ public class RestManager { public Registry() { reservedEndpoints.add(SCHEMA_BASE_PATH + MANAGED_ENDPOINT); - - for (String reservedEndpoint : SolrSchemaRestApi.getReservedEndpoints()) { - reservedEndpoints.add(reservedEndpoint); - } - reservedEndpointsPattern = getReservedEndpointsPattern(); } @@ -210,7 +202,7 @@ public class RestManager { // it's ok to re-register the same class for an existing path ManagedResourceRegistration reg = registered.get(resourceId); if (reg != null) { - if (!reg.implClass.equals(implClass)) { + if (!implClass.equals(reg.implClass)) { String errMsg = String.format(Locale.ROOT, "REST API path %s already registered to instances of %s", resourceId, reg.implClass.getName()); @@ -240,46 +232,42 @@ public class RestManager { } /** - * Locates the RestManager using ThreadLocal SolrRequestInfo. + * Request handling needs a lightweight object to delegate a request to. + * ManagedResource implementations are heavy-weight objects that live for the duration of + * a SolrCore, so this class acts as the proxy between the request handler and a + * ManagedResource when doing request processing. */ - public static RestManager getRestManager(SolrRequestInfo solrRequestInfo) { - if (solrRequestInfo == null) - throw new ResourceException(Status.SERVER_ERROR_INTERNAL, - "No SolrRequestInfo in this Thread!"); + public static class ManagedEndpoint extends BaseSolrResource { + + final RestManager restManager; + + public ManagedEndpoint(RestManager restManager) { + this.restManager = restManager; + } - SolrQueryRequest req = solrRequestInfo.getReq(); - RestManager restManager = - (req != null) ? req.getCore().getRestManager() : null; - - if (restManager == null) - throw new ResourceException(Status.SERVER_ERROR_INTERNAL, - "No RestManager found!"); - - return restManager; - } - - /** - * The Restlet router needs a lightweight extension of ServerResource to delegate a request - * to. ManagedResource implementations are heavy-weight objects that live for the duration of - * a SolrCore, so this class acts as the proxy between Restlet and a ManagedResource when - * doing request processing. - * - */ - public static class ManagedEndpoint extends BaseSolrResource - implements GETable, PUTable, POSTable, DELETEable - { /** - * Determines the ManagedResource resourceId from the Restlet request. + * Determines the ManagedResource resourceId from the request path. */ - public static String resolveResourceId(Request restletReq) { - String resourceId = restletReq.getResourceRef(). - getRelativeRef(restletReq.getRootRef().getParentRef()).getPath(DECODE); - + public static String resolveResourceId(final String path) { + String resourceId; + try { + resourceId = URLDecoder.decode(path, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); // shouldn't happen + } + + int at = resourceId.indexOf("/schema"); + if (at == -1) { + at = resourceId.indexOf("/config"); + } + if (at > 0) { + resourceId = resourceId.substring(at); + } + // all resources are registered with the leading slash if (!resourceId.startsWith("/")) resourceId = "/"+resourceId; - return resourceId; } @@ -292,18 +280,11 @@ public class RestManager { * dynamically locate the ManagedResource associated with the request URI. */ @Override - public void doInit() throws ResourceException { - super.doInit(); - - // get the relative path to the requested resource, which is - // needed to locate ManagedResource impls at runtime - String resourceId = resolveResourceId(getRequest()); + public void doInit(SolrQueryRequest solrRequest, SolrQueryResponse solrResponse) { + super.doInit(solrRequest, solrResponse); - // supports a request for a registered resource or its child - RestManager restManager = - RestManager.getRestManager(SolrRequestInfo.getRequestInfo()); - - managedResource = restManager.getManagedResourceOrNull(resourceId); + final String resourceId = resolveResourceId(solrRequest.getPath()); + managedResource = restManager.getManagedResourceOrNull(resourceId); if (managedResource == null) { // see if we have a registered endpoint one-level up ... int lastSlashAt = resourceId.lastIndexOf('/'); @@ -317,7 +298,7 @@ public class RestManager { if (!(managedResource instanceof ManagedResource.ChildResourceSupport)) { String errMsg = String.format(Locale.ROOT, "%s does not support child resources!", managedResource.getResourceId()); - throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, errMsg); + throw new SolrException(ErrorCode.BAD_REQUEST, errMsg); } childId = resourceId.substring(lastSlashAt+1); @@ -326,44 +307,46 @@ public class RestManager { } } } - + if (managedResource == null) { - if (Method.PUT.equals(getMethod()) || Method.POST.equals(getMethod())) { + final String method = getSolrRequest().getHttpMethod(); + if ("PUT".equals(method) || "POST".equals(method)) { // delegate create requests to the RestManager managedResource = restManager.endpoint; - } else { - throw new ResourceException(Status.CLIENT_ERROR_NOT_FOUND, + } else { + throw new SolrException(ErrorCode.BAD_REQUEST, "No REST managed resource registered for path "+resourceId); } } - - log.info("Found ManagedResource [{}] for {}", managedResource, resourceId); - } - - @Override - public Representation put(Representation entity) { - try { - managedResource.doPut(this, entity, parseJsonFromRequestBody(entity)); - } catch (Exception e) { - getSolrResponse().setException(e); - } - handlePostExecution(log); - return new SolrOutputRepresentation(); - } - - @Override - public Representation post(Representation entity) { - try { - managedResource.doPost(this, entity, parseJsonFromRequestBody(entity)); - } catch (Exception e) { - getSolrResponse().setException(e); - } - handlePostExecution(log); - return new SolrOutputRepresentation(); - } - @Override - public Representation delete() { + log.info("Found ManagedResource [{}] for {}", managedResource, resourceId); + } + + public void delegateRequestToManagedResource() { + SolrQueryRequest req = getSolrRequest(); + final String method = req.getHttpMethod(); + try { + switch (method) { + case "GET": + managedResource.doGet(this, childId); + break; + case "PUT": + managedResource.doPut(this, parseJsonFromRequestBody(req)); + break; + case "POST": + managedResource.doPost(this, parseJsonFromRequestBody(req)); + break; + case "DELETE": + doDelete(); + break; + } + } catch (Exception e) { + getSolrResponse().setException(e); + } + handlePostExecution(log); + } + + protected void doDelete() { // only delegate delete child resources to the ManagedResource // as deleting the actual resource is best handled by the // RestManager @@ -375,68 +358,24 @@ public class RestManager { } } else { try { - RestManager restManager = - RestManager.getRestManager(SolrRequestInfo.getRequestInfo()); restManager.deleteManagedResource(managedResource); } catch (Exception e) { getSolrResponse().setException(e); } } handlePostExecution(log); - return new SolrOutputRepresentation(); - } - - @Override - public Representation get() { - try { - managedResource.doGet(this, childId); - } catch (Exception e) { - getSolrResponse().setException(e); - } - handlePostExecution(log); - return new SolrOutputRepresentation(); - } - - /** - * Parses and validates the JSON passed from the to the ManagedResource. - */ - protected Object parseJsonFromRequestBody(Representation entity) { - if (entity.getMediaType() == null) { - entity.setMediaType(MediaType.APPLICATION_JSON); - } - - if (!entity.getMediaType().equals(MediaType.APPLICATION_JSON, true)) { - String errMsg = String.format(Locale.ROOT, - "Invalid content type %s; only %s is supported.", - entity.getMediaType(), MediaType.APPLICATION_JSON.toString()); - log.error(errMsg); - throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, errMsg); - } - - String text = null; - try { - text = entity.getText(); - } catch (IOException ioExc) { - String errMsg = "Failed to read entity text due to: "+ioExc; - log.error(errMsg, ioExc); - throw new ResourceException(Status.SERVER_ERROR_INTERNAL, errMsg, ioExc); - } - - if (text == null || text.trim().length() == 0) { - throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "Empty request body!"); - } + } - Object parsedJson = null; - try { - parsedJson = fromJSONString(text); - } catch (Exception ioExc) { - String errMsg = String.format(Locale.ROOT, - "Failed to parse request [%s] into JSON due to: %s", - text, ioExc.toString()); - log.error(errMsg, ioExc); - throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, errMsg, ioExc); + protected Object parseJsonFromRequestBody(SolrQueryRequest req) { + Iterator iter = req.getContentStreams().iterator(); + if (iter.hasNext()) { + try (Reader reader = iter.next().getReader()) { + return fromJSON(reader); + } catch (IOException ioExc) { + throw new SolrException(ErrorCode.SERVER_ERROR, ioExc); + } } - return parsedJson; + throw new SolrException(ErrorCode.BAD_REQUEST, "No JSON body found in request!"); } @Override @@ -518,16 +457,16 @@ public class RestManager { */ @SuppressWarnings("unchecked") @Override - public synchronized void doPut(BaseSolrResource endpoint, Representation entity, Object json) { + public synchronized void doPut(BaseSolrResource endpoint, Object json) { if (json instanceof Map) { - String resourceId = ManagedEndpoint.resolveResourceId(endpoint.getRequest()); + String resourceId = ManagedEndpoint.resolveResourceId(endpoint.getSolrRequest().getPath()); Map info = (Map)json; info.put("resourceId", resourceId); storeManagedData(applyUpdatesToManagedData(json)); } else { - throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, + throw new SolrException(ErrorCode.BAD_REQUEST, "Expected Map to create a new ManagedResource but received a "+json.getClass().getName()); - } + } // PUT just returns success status code with an empty body } @@ -539,15 +478,15 @@ public class RestManager { @SuppressWarnings("unchecked") @Override protected Object applyUpdatesToManagedData(Object updates) { - Map info = (Map)updates; + Map info = (Map)updates; // this is where we'd register a new ManagedResource String implClass = info.get("class"); String resourceId = info.get("resourceId"); - log.info("Creating a new ManagedResource of type {} at path {}", + log.info("Creating a new ManagedResource of type {} at path {}", implClass, resourceId); - Class clazz = + Class clazz = solrResourceLoader.findClass(implClass, ManagedResource.class); - + // add this new resource to the RestManager restManager.addManagedResource(resourceId, clazz); @@ -558,7 +497,7 @@ public class RestManager { if (reg.observers.isEmpty()) { managedList.add(reg.getInfo()); } - } + } return managedList; } @@ -567,18 +506,18 @@ public class RestManager { */ @Override public void doDeleteChild(BaseSolrResource endpoint, String childId) { - throw new ResourceException(Status.SERVER_ERROR_NOT_IMPLEMENTED); + throw new SolrException(ErrorCode.BAD_REQUEST, "Delete child resource not supported!"); } @Override public void doGet(BaseSolrResource endpoint, String childId) { // filter results by /schema or /config - String path = ManagedEndpoint.resolveResourceId(endpoint.getRequest()); + String path = ManagedEndpoint.resolveResourceId(endpoint.getSolrRequest().getPath()); Matcher resourceIdMatcher = resourceIdRegex.matcher(path); if (!resourceIdMatcher.matches()) { // extremely unlikely but didn't want to squelch it either - throw new ResourceException(Status.SERVER_ERROR_NOT_IMPLEMENTED, path); + throw new SolrException(ErrorCode.BAD_REQUEST, "Requests to path "+path+" not supported!"); } String filter = resourceIdMatcher.group(1); @@ -603,11 +542,7 @@ public class RestManager { protected Map managed = new TreeMap<>(); protected RestManagerManagedResource endpoint; protected SolrResourceLoader loader; - - // refs to these are needed to bind new ManagedResources created using the API - protected Router schemaRouter; - protected Router configRouter; - + /** * Initializes the RestManager with the storageIO being optionally created outside of this implementation * such as to use ZooKeeper instead of the local FS. @@ -625,7 +560,7 @@ public class RestManager { this.storageIO = storageIO; this.loader = loader; - + registry = loader.getManagedResourceRegistry(); // the RestManager provides metadata about managed resources via the /managed endpoint @@ -651,8 +586,7 @@ public class RestManager { /** * If not already registered, registers the given {@link ManagedResource} subclass - * at the given resourceId, creates an instance, and attaches it to the appropriate - * Restlet router. Returns the corresponding instance. + * at the given resourceId, creates an instance. Returns the corresponding instance. */ public synchronized ManagedResource addManagedResource(String resourceId, Class clazz) { final ManagedResource res; @@ -665,31 +599,16 @@ public class RestManager { } return res; } - - // used internally to create and attach a ManagedResource to the Restlet router - // the registry also uses this method directly, which is slightly hacky but necessary - // in order to support dynamic adding of new fieldTypes using the managed-schema API + + // cache a mapping of path to ManagedResource private synchronized ManagedResource addRegisteredResource(ManagedResourceRegistration reg) { String resourceId = reg.resourceId; ManagedResource res = createManagedResource(reg); managed.put(resourceId, res); log.info("Registered new managed resource {}", resourceId); - - // attach this new resource to the Restlet router - Matcher resourceIdValidator = resourceIdRegex.matcher(resourceId); - boolean validated = resourceIdValidator.matches(); - assert validated : "managed resourceId '" + resourceId - + "' should already be validated by registerManagedResource()"; - String routerPath = resourceIdValidator.group(1); - String path = resourceIdValidator.group(2); - Router router = SCHEMA_BASE_PATH.equals(routerPath) ? schemaRouter : configRouter; - if (router != null) { - attachManagedResource(res, path, router); - } return res; } - /** * Creates a ManagedResource using registration information. */ @@ -714,14 +633,13 @@ public class RestManager { * Returns the {@link ManagedResource} subclass instance corresponding * to the given resourceId from the registry. * - * @throws ResourceException if no managed resource is registered with + * @throws SolrException if no managed resource is registered with * the given resourceId. */ public ManagedResource getManagedResource(String resourceId) { ManagedResource res = getManagedResourceOrNull(resourceId); if (res == null) { - throw new ResourceException(Status.SERVER_ERROR_INTERNAL, - "No ManagedResource registered for path: "+resourceId); + throw new SolrException(ErrorCode.NOT_FOUND, "No ManagedResource registered for path: "+resourceId); } return res; } @@ -759,48 +677,5 @@ public class RestManager { log.error("Error when trying to clean-up after deleting {}",resourceId, e); } } - - /** - * Attach managed resource paths to the given Restlet Router. - * @param router - Restlet Router - */ - public synchronized void attachManagedResources(String routerPath, Router router) { - if (SCHEMA_BASE_PATH.equals(routerPath)) { - this.schemaRouter = router; - } else { - throw new SolrException(ErrorCode.SERVER_ERROR, - routerPath+" not supported by the RestManager"); - } - - int numAttached = 0; - for (Map.Entry entry : managed.entrySet()) { - String resourceId = entry.getKey(); - if (resourceId.startsWith(routerPath)) { - // the way restlet works is you attach a path w/o the routerPath - String path = resourceId.substring(routerPath.length()); - attachManagedResource(entry.getValue(), path, router); - ++numAttached; - } - } - - log.info("Attached {} ManagedResource endpoints to Restlet router: {}", - numAttached, routerPath); - } - - /** - * Attaches a ManagedResource and optionally a path for child resources - * to the given Restlet Router. - */ - protected void attachManagedResource(ManagedResource res, String path, Router router) { - router.attach(path, res.getServerResourceClass()); - log.info("Attached managed resource at path: {}",path); - - // Determine if we should also route requests for child resources - // ManagedResource.ChildResourceSupport is a marker interface that - // indicates the ManagedResource also manages child resources at - // a path one level down from the main resourceId - if (ManagedResource.ChildResourceSupport.class.isAssignableFrom(res.getClass())) { - router.attach(path+"/{child}", res.getServerResourceClass()); - } - } + } diff --git a/solr/core/src/java/org/apache/solr/rest/SolrSchemaRestApi.java b/solr/core/src/java/org/apache/solr/rest/SolrSchemaRestApi.java deleted file mode 100644 index aa7826a5da6..00000000000 --- a/solr/core/src/java/org/apache/solr/rest/SolrSchemaRestApi.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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.solr.rest; - -import java.lang.invoke.MethodHandles; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import org.apache.solr.request.SolrRequestInfo; -import org.restlet.Application; -import org.restlet.Restlet; -import org.restlet.routing.Router; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Restlet servlet handling /<context>/<collection>/schema/* URL paths - */ -public class SolrSchemaRestApi extends Application { - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - - /** - * Returns reserved endpoints under /schema - */ - public static Set getReservedEndpoints() { - Set reservedEndpoints = new HashSet<>(); - return Collections.unmodifiableSet(reservedEndpoints); - } - - private Router router; - - public SolrSchemaRestApi() { - router = new Router(getContext()); - } - - @Override - public void stop() throws Exception { - if (null != router) { - router.stop(); - } - } - - /** - * Bind URL paths to the appropriate ServerResource subclass. - */ - @Override - public synchronized Restlet createInboundRoot() { - - log.info("createInboundRoot started for /schema"); - - - router.attachDefault(RestManager.ManagedEndpoint.class); - - // attach all the dynamically registered schema resources - RestManager.getRestManager(SolrRequestInfo.getRequestInfo()) - .attachManagedResources(RestManager.SCHEMA_BASE_PATH, router); - - log.info("createInboundRoot complete for /schema"); - - return router; - } -} diff --git a/solr/core/src/java/org/apache/solr/rest/package-info.java b/solr/core/src/java/org/apache/solr/rest/package-info.java index b903928ee4e..ef642aabeaf 100644 --- a/solr/core/src/java/org/apache/solr/rest/package-info.java +++ b/solr/core/src/java/org/apache/solr/rest/package-info.java @@ -16,7 +16,7 @@ */ /** - * Solr RESTful APIs via Restlet. + * Solr RESTful APIs. */ package org.apache.solr.rest; diff --git a/solr/core/src/java/org/apache/solr/rest/schema/analysis/ManagedSynonymFilterFactory.java b/solr/core/src/java/org/apache/solr/rest/schema/analysis/ManagedSynonymFilterFactory.java index 69dcf8050ec..da256977b16 100644 --- a/solr/core/src/java/org/apache/solr/rest/schema/analysis/ManagedSynonymFilterFactory.java +++ b/solr/core/src/java/org/apache/solr/rest/schema/analysis/ManagedSynonymFilterFactory.java @@ -43,8 +43,6 @@ import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.rest.BaseSolrResource; import org.apache.solr.rest.ManagedResource; import org.apache.solr.rest.ManagedResourceStorage.StorageIO; -import org.restlet.data.Status; -import org.restlet.resource.ResourceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -180,7 +178,7 @@ public class ManagedSynonymFilterFactory extends BaseManagedTokenFilterFactory { } else if (updates instanceof Map) { madeChanges = applyMapUpdates((Map)updates, ignoreCase); } else { - throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, + throw new SolrException(ErrorCode.BAD_REQUEST, "Unsupported data format (" + updates.getClass().getName() + "); expected a JSON object (Map or List)!"); } return madeChanges ? getStoredView() : null; @@ -250,7 +248,7 @@ public class ManagedSynonymFilterFactory extends BaseManagedTokenFilterFactory { } } else { - throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "Unsupported value "+val+ + throw new SolrException(ErrorCode.BAD_REQUEST, "Unsupported value "+val+ " for "+term+"; expected single value or a JSON array!"); } diff --git a/solr/core/src/java/org/apache/solr/rest/schema/analysis/ManagedSynonymGraphFilterFactory.java b/solr/core/src/java/org/apache/solr/rest/schema/analysis/ManagedSynonymGraphFilterFactory.java index 0f00947d784..fa11c84ee07 100644 --- a/solr/core/src/java/org/apache/solr/rest/schema/analysis/ManagedSynonymGraphFilterFactory.java +++ b/solr/core/src/java/org/apache/solr/rest/schema/analysis/ManagedSynonymGraphFilterFactory.java @@ -42,8 +42,6 @@ import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.rest.BaseSolrResource; import org.apache.solr.rest.ManagedResource; import org.apache.solr.rest.ManagedResourceStorage.StorageIO; -import org.restlet.data.Status; -import org.restlet.resource.ResourceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -175,7 +173,7 @@ public class ManagedSynonymGraphFilterFactory extends BaseManagedTokenFilterFact } else if (updates instanceof Map) { madeChanges = applyMapUpdates((Map)updates, ignoreCase); } else { - throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, + throw new SolrException(ErrorCode.BAD_REQUEST, "Unsupported data format (" + updates.getClass().getName() + "); expected a JSON object (Map or List)!"); } return madeChanges ? getStoredView() : null; @@ -245,7 +243,7 @@ public class ManagedSynonymGraphFilterFactory extends BaseManagedTokenFilterFact } } else { - throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "Unsupported value "+val+ + throw new SolrException(ErrorCode.BAD_REQUEST, "Unsupported value "+val+ " for "+term+"; expected single value or a JSON array!"); } diff --git a/solr/core/src/java/org/apache/solr/rest/schema/analysis/package-info.java b/solr/core/src/java/org/apache/solr/rest/schema/analysis/package-info.java index 04d4428c3e6..812418820b6 100644 --- a/solr/core/src/java/org/apache/solr/rest/schema/analysis/package-info.java +++ b/solr/core/src/java/org/apache/solr/rest/schema/analysis/package-info.java @@ -16,7 +16,8 @@ */ /** - * Analysis-related functionality for RESTful API access to the Solr Schema using Restlet. + * Analysis-related functionality for RESTful API access to managed resources related to the schema, such + * as stopwords, protected words, and synonyms. */ package org.apache.solr.rest.schema.analysis; diff --git a/solr/core/src/java/org/apache/solr/rest/schema/package-info.java b/solr/core/src/java/org/apache/solr/rest/schema/package-info.java index ca5fd2c6312..37123592f2e 100644 --- a/solr/core/src/java/org/apache/solr/rest/schema/package-info.java +++ b/solr/core/src/java/org/apache/solr/rest/schema/package-info.java @@ -16,7 +16,7 @@ */ /** - * Provides RESTful API access to the Solr Schema using Restlet. + * Provides RESTful API access to managed resources in the Solr Schema. */ package org.apache.solr.rest.schema; diff --git a/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java b/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java index a24d025238c..4fae6141259 100644 --- a/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java +++ b/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java @@ -408,26 +408,6 @@ public class HttpSolrCall { protected void extractHandlerFromURLPath(SolrRequestParsers parser) throws Exception { if (handler == null && path.length() > 1) { // don't match "" or "/" as valid path handler = core.getRequestHandler(path); - - if (handler == null) { - //may be a restlet path - // Handle /schema/* paths via Restlet - if (path.equals("/schema") || path.startsWith("/schema/")) { - solrReq = parser.parse(core, path, req); - SolrRequestInfo.setRequestInfo(new SolrRequestInfo(solrReq, new SolrQueryResponse())); - mustClearSolrRequestInfo = true; - if (path.equals(req.getServletPath())) { - // avoid endless loop - pass through to Restlet via webapp - action = PASSTHROUGH; - } else { - // forward rewritten URI (without path prefix and core/collection name) to Restlet - action = FORWARD; - } - SolrRequestInfo.getRequestInfo().setAction(action); - return; - } - } - // no handler yet but allows us to handle /select with a 'qt' param if (handler == null && parser.isHandleSelect()) { if ("/select".equals(path) || "/select/".equals(path)) { diff --git a/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java b/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java index 967dffbed30..01630a8d156 100644 --- a/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java +++ b/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java @@ -120,8 +120,8 @@ public class SolrDispatchFilter extends BaseSolrFilter { /** * Enum to define action that needs to be processed. - * PASSTHROUGH: Pass through to Restlet via webapp. - * FORWARD: Forward rewritten URI (without path prefix and core/collection name) to Restlet + * PASSTHROUGH: Pass through to another filter via webapp. + * FORWARD: Forward rewritten URI (without path prefix and core/collection name) to another filter in the chain * RETURN: Returns the control, and no further specific processing is needed. * This is generally when an error is set and returned. * RETRY:Retry the request. In cases when a core isn't found to work with, this is set. diff --git a/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java b/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java index 4a8cffaf679..2592950c996 100644 --- a/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java +++ b/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java @@ -768,8 +768,7 @@ public class SolrRequestParsers { // According to previous StandardRequestParser logic (this is a re-written version), // POST was handled normally, but other methods (PUT/DELETE) - // were handled by restlet if the URI contained /schema or /config - // "handled by restlet" means that we don't attempt to handle any request body here. + // were handled by the RestManager classes if the URI contained /schema or /config if (!isPost) { if (isV2) { return raw.parseParamsAndFillStreams(req, streams); @@ -780,14 +779,14 @@ public class SolrRequestParsers { // OK, we have a BODY at this point - boolean restletPath = false; + boolean schemaRestPath = false; int idx = uri.indexOf("/schema"); if (idx >= 0 && uri.endsWith("/schema") || uri.contains("/schema/")) { - restletPath = true; + schemaRestPath = true; } - if (restletPath) { - return parseQueryString(req.getQueryString()); + if (schemaRestPath) { + return raw.parseParamsAndFillStreams(req, streams); } if ("PUT".equals(method) || "DELETE".equals(method)) { diff --git a/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java b/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java index d37a5442140..c673809d186 100644 --- a/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java +++ b/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java @@ -51,7 +51,6 @@ import org.eclipse.jetty.servlet.ServletHolder; import org.junit.After; import org.junit.Before; import org.noggit.JSONParser; -import org.restlet.ext.servlet.ServerServlet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -122,9 +121,6 @@ public class TestSolrConfigHandler extends RestTestBase { FileUtils.copyDirectory(new File(TEST_HOME()), tmpSolrHome.getAbsoluteFile()); final SortedMap extraServlets = new TreeMap<>(); - final ServletHolder solrRestApi = new ServletHolder("SolrSchemaRestApi", ServerServlet.class); - solrRestApi.setInitParameter("org.restlet.application", "org.apache.solr.rest.SolrSchemaRestApi"); - extraServlets.put(solrRestApi, "/schema/*"); // '/schema/*' matches '/schema', '/schema/', and '/schema/whatever...' System.setProperty("managed.schema.mutable", "true"); System.setProperty("enable.update.log", "false"); diff --git a/solr/core/src/test/org/apache/solr/request/TestStreamBody.java b/solr/core/src/test/org/apache/solr/request/TestStreamBody.java index ab4648df765..181a0080e00 100644 --- a/solr/core/src/test/org/apache/solr/request/TestStreamBody.java +++ b/solr/core/src/test/org/apache/solr/request/TestStreamBody.java @@ -32,7 +32,6 @@ import org.eclipse.jetty.servlet.ServletHolder; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.restlet.ext.servlet.ServerServlet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,9 +49,6 @@ public class TestStreamBody extends RestTestBase { FileUtils.copyDirectory(new File(TEST_HOME()), tmpSolrHome.getAbsoluteFile()); final SortedMap extraServlets = new TreeMap<>(); - final ServletHolder solrRestApi = new ServletHolder("SolrSchemaRestApi", ServerServlet.class); - solrRestApi.setInitParameter("org.restlet.application", "org.apache.solr.rest.SolrSchemaRestApi"); - extraServlets.put(solrRestApi, "/schema/*"); // '/schema/*' matches '/schema', '/schema/', and '/schema/whatever...' System.setProperty("managed.schema.mutable", "true"); System.setProperty("enable.update.log", "false"); diff --git a/solr/core/src/test/org/apache/solr/rest/SolrRestletTestBase.java b/solr/core/src/test/org/apache/solr/rest/SolrRestletTestBase.java index 5ce6a9e092c..354d316c0b8 100644 --- a/solr/core/src/test/org/apache/solr/rest/SolrRestletTestBase.java +++ b/solr/core/src/test/org/apache/solr/rest/SolrRestletTestBase.java @@ -18,7 +18,6 @@ package org.apache.solr.rest; import org.apache.solr.util.RestTestBase; import org.eclipse.jetty.servlet.ServletHolder; import org.junit.BeforeClass; -import org.restlet.ext.servlet.ServerServlet; import java.nio.file.Path; import java.util.Properties; @@ -26,9 +25,8 @@ import java.util.SortedMap; import java.util.TreeMap; /** - * Base class for Solr Restlet-based tests. Creates jetty and test harness - * with solrconfig.xml and schema-rest.xml, including "extra" servlets for - * all Solr Restlet Application subclasses. + * Base class for Solr Rest-oriented API tests. Creates jetty and test harness + * with solrconfig.xml and schema-rest.xml. * * Use RestTestBase instead if you need to specialize the solrconfig, * the schema, or jetty/test harness creation; otherwise you'll get @@ -51,9 +49,6 @@ abstract public class SolrRestletTestBase extends RestTestBase { System.setProperty("configSetBaseDir", TEST_HOME()); final SortedMap extraServlets = new TreeMap<>(); - final ServletHolder solrSchemaRestApi = new ServletHolder("SolrSchemaRestApi", ServerServlet.class); - solrSchemaRestApi.setInitParameter("org.restlet.application", "org.apache.solr.rest.SolrSchemaRestApi"); - extraServlets.put(solrSchemaRestApi, "/schema/*"); // '/schema/*' matches '/schema', '/schema/', and '/schema/whatever...' Properties props = new Properties(); props.setProperty("name", DEFAULT_TEST_CORENAME); diff --git a/solr/core/src/test/org/apache/solr/rest/TestRestManager.java b/solr/core/src/test/org/apache/solr/rest/TestRestManager.java index b4aff0b1ea5..bfe1f119637 100644 --- a/solr/core/src/test/org/apache/solr/rest/TestRestManager.java +++ b/solr/core/src/test/org/apache/solr/rest/TestRestManager.java @@ -19,146 +19,19 @@ package org.apache.solr.rest; import java.io.File; import java.nio.file.Paths; import java.util.Arrays; -import java.util.Locale; -import java.util.Set; -import org.apache.solr.common.SolrException; import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.Utils; import org.apache.solr.core.SolrResourceLoader; import org.apache.solr.rest.ManagedResourceStorage.StorageIO; import org.apache.solr.rest.schema.analysis.ManagedWordSetResource; -import org.junit.Ignore; import org.junit.Test; -import org.restlet.Request; -import org.restlet.data.Reference; /** * Tests {@link RestManager} functionality, including resource registration, * and REST API requests and responses. */ public class TestRestManager extends SolrRestletTestBase { - - private class BogusManagedResource extends ManagedResource { - - protected BogusManagedResource(String resourceId, - SolrResourceLoader loader, StorageIO storageIO) throws SolrException { - super(resourceId, loader, storageIO); - } - - @Override - protected void onManagedDataLoadedFromStorage(NamedList managedInitArgs, Object managedData) - throws SolrException {} - - @Override - protected Object applyUpdatesToManagedData(Object updates) { - return null; - } - - @Override - public void doDeleteChild(BaseSolrResource endpoint, String childId) {} - - @Override - public void doGet(BaseSolrResource endpoint, String childId) {} - - } - - private static class MockAnalysisComponent implements ManagedResourceObserver { - - @Override - public void onManagedResourceInitialized(NamedList args, ManagedResource res) - throws SolrException { - assertTrue(res instanceof ManagedWordSetResource); - } - } - - /** - * Test RestManager initialization and handling of registered ManagedResources. - */ - @Test - @Ignore - public void testManagedResourceRegistrationAndInitialization() throws Exception { - // first, we need to register some ManagedResources, which is done with the registry - // provided by the SolrResourceLoader - SolrResourceLoader loader = new SolrResourceLoader(Paths.get("./")); - - RestManager.Registry registry = loader.getManagedResourceRegistry(); - assertNotNull("Expected a non-null RestManager.Registry from the SolrResourceLoader!", registry); - - String resourceId = "/config/test/foo"; - registry.registerManagedResource(resourceId, - ManagedWordSetResource.class, - new MockAnalysisComponent()); - - // verify the two different components can register the same ManagedResource in the registry - registry.registerManagedResource(resourceId, - ManagedWordSetResource.class, - new MockAnalysisComponent()); - - // verify we can register another resource under a different resourceId - registry.registerManagedResource("/config/test/foo2", - ManagedWordSetResource.class, - new MockAnalysisComponent()); - - ignoreException("REST API path .* already registered to instances of "); - - String failureMessage = "Should not be able to register a different" - + " ManagedResource implementation for {}"; - - // verify that some other hooligan cannot register another type - // of ManagedResource implementation under the same resourceId - try { - registry.registerManagedResource(resourceId, - BogusManagedResource.class, - new MockAnalysisComponent()); - fail(String.format(Locale.ROOT, failureMessage, resourceId)); - } catch (SolrException solrExc) { - // expected output - } - - resetExceptionIgnores(); - - ignoreException("is a reserved endpoint used by the Solr REST API!"); - - failureMessage = "Should not be able to register reserved endpoint {}"; - - // verify that already-spoken-for REST API endpoints can't be registered - Set reservedEndpoints = registry.getReservedEndpoints(); - assertTrue(reservedEndpoints.size() > 2); - assertTrue(reservedEndpoints.contains(RestManager.SCHEMA_BASE_PATH + RestManager.MANAGED_ENDPOINT)); - for (String endpoint : reservedEndpoints) { - - try { - registry.registerManagedResource - (endpoint, BogusManagedResource.class, new MockAnalysisComponent()); - fail(String.format(Locale.ROOT, failureMessage, endpoint)); - } catch (SolrException solrExc) { - // expected output - } - - // also try to register already-spoken-for REST API endpoints with a child segment - endpoint += "/kid"; - try { - registry.registerManagedResource - (endpoint, BogusManagedResource.class, new MockAnalysisComponent()); - fail(String.format(Locale.ROOT, failureMessage, endpoint)); - } catch (SolrException solrExc) { - // expected output - } - } - - resetExceptionIgnores(); - - NamedList initArgs = new NamedList<>(); - RestManager restManager = new RestManager(); - restManager.init(loader, initArgs, new ManagedResourceStorage.InMemoryStorageIO()); - - ManagedResource res = restManager.getManagedResource(resourceId); - assertTrue(res instanceof ManagedWordSetResource); - assertEquals(res.getResourceId(), resourceId); - - restManager.getManagedResource("/config/test/foo2"); // exception if it isn't registered - } /** * Tests {@link RestManager}'s responses to REST API requests on /config/managed @@ -255,27 +128,15 @@ public class TestRestManager extends SolrRestletTestBase { @Test public void testResolveResourceId () throws Exception { - Request testRequest = new Request(); - Reference rootRef = new Reference("http://solr.apache.org/"); - testRequest.setRootRef(rootRef); - - Reference resourceRef = new Reference("http://solr.apache.org/schema/analysis/synonyms/de"); - testRequest.setResourceRef(resourceRef); - - String resourceId = RestManager.ManagedEndpoint.resolveResourceId(testRequest); + String path = "http://solr.apache.org/schema/analysis/synonyms/de"; + String resourceId = RestManager.ManagedEndpoint.resolveResourceId(path); assertEquals(resourceId, "/schema/analysis/synonyms/de"); } @Test public void testResolveResourceIdDecodeUrlEntities () throws Exception { - Request testRequest = new Request(); - Reference rootRef = new Reference("http://solr.apache.org/"); - testRequest.setRootRef(rootRef); - - Reference resourceRef = new Reference("http://solr.apache.org/schema/analysis/synonyms/de/%C3%84ndern"); - testRequest.setResourceRef(resourceRef); - - String resourceId = RestManager.ManagedEndpoint.resolveResourceId(testRequest); + String path = "http://solr.apache.org/schema/analysis/synonyms/de/%C3%84ndern"; + String resourceId = RestManager.ManagedEndpoint.resolveResourceId(path); assertEquals(resourceId, "/schema/analysis/synonyms/de/Ă„ndern"); } } diff --git a/solr/core/src/test/org/apache/solr/rest/schema/TestSerializedLuceneMatchVersion.java b/solr/core/src/test/org/apache/solr/rest/schema/TestSerializedLuceneMatchVersion.java index f50d669dc8c..4750b0fde70 100644 --- a/solr/core/src/test/org/apache/solr/rest/schema/TestSerializedLuceneMatchVersion.java +++ b/solr/core/src/test/org/apache/solr/rest/schema/TestSerializedLuceneMatchVersion.java @@ -19,7 +19,6 @@ import org.apache.solr.util.RestTestBase; import org.eclipse.jetty.servlet.ServletHolder; import org.junit.BeforeClass; import org.junit.Test; -import org.restlet.ext.servlet.ServerServlet; import java.util.SortedMap; import java.util.TreeMap; @@ -30,9 +29,6 @@ public class TestSerializedLuceneMatchVersion extends RestTestBase { @BeforeClass public static void init() throws Exception { final SortedMap extraServlets = new TreeMap<>(); - final ServletHolder solrRestApi = new ServletHolder("SolrSchemaRestApi", ServerServlet.class); - solrRestApi.setInitParameter("org.restlet.application", "org.apache.solr.rest.SolrSchemaRestApi"); - extraServlets.put(solrRestApi, "/schema/*"); // '/schema/*' matches '/schema', '/schema/', and '/schema/whatever...' createJettyAndHarness(TEST_HOME(), "solrconfig-minimal.xml", "schema-rest-lucene-match-version.xml", "/solr", true, extraServlets); diff --git a/solr/core/src/test/org/apache/solr/rest/schema/analysis/TestManagedStopFilterFactory.java b/solr/core/src/test/org/apache/solr/rest/schema/analysis/TestManagedStopFilterFactory.java index 4950ac41461..d41132534f2 100644 --- a/solr/core/src/test/org/apache/solr/rest/schema/analysis/TestManagedStopFilterFactory.java +++ b/solr/core/src/test/org/apache/solr/rest/schema/analysis/TestManagedStopFilterFactory.java @@ -28,7 +28,6 @@ import org.eclipse.jetty.servlet.ServletHolder; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.restlet.ext.servlet.ServerServlet; /** * Test the REST API for managing stop words, which is pretty basic: @@ -49,9 +48,6 @@ public class TestManagedStopFilterFactory extends RestTestBase { FileUtils.copyDirectory(new File(TEST_HOME()), tmpSolrHome.getAbsoluteFile()); final SortedMap extraServlets = new TreeMap<>(); - final ServletHolder solrRestApi = new ServletHolder("SolrSchemaRestApi", ServerServlet.class); - solrRestApi.setInitParameter("org.restlet.application", "org.apache.solr.rest.SolrSchemaRestApi"); - extraServlets.put(solrRestApi, "/schema/*"); // '/schema/*' matches '/schema', '/schema/', and '/schema/whatever...' System.setProperty("managed.schema.mutable", "true"); System.setProperty("enable.update.log", "false"); diff --git a/solr/core/src/test/org/apache/solr/rest/schema/analysis/TestManagedSynonymFilterFactory.java b/solr/core/src/test/org/apache/solr/rest/schema/analysis/TestManagedSynonymFilterFactory.java index 603249befb0..8740cec6ca8 100644 --- a/solr/core/src/test/org/apache/solr/rest/schema/analysis/TestManagedSynonymFilterFactory.java +++ b/solr/core/src/test/org/apache/solr/rest/schema/analysis/TestManagedSynonymFilterFactory.java @@ -32,7 +32,6 @@ import org.eclipse.jetty.servlet.ServletHolder; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.restlet.ext.servlet.ServerServlet; import static org.apache.solr.common.util.Utils.toJSONString; @@ -49,9 +48,6 @@ public class TestManagedSynonymFilterFactory extends RestTestBase { FileUtils.copyDirectory(new File(TEST_HOME()), tmpSolrHome.getAbsoluteFile()); final SortedMap extraServlets = new TreeMap<>(); - final ServletHolder solrRestApi = new ServletHolder("SolrSchemaRestApi", ServerServlet.class); - solrRestApi.setInitParameter("org.restlet.application", "org.apache.solr.rest.SolrSchemaRestApi"); - extraServlets.put(solrRestApi, "/schema/*"); System.setProperty("managed.schema.mutable", "true"); System.setProperty("enable.update.log", "false"); diff --git a/solr/core/src/test/org/apache/solr/rest/schema/analysis/TestManagedSynonymGraphFilterFactory.java b/solr/core/src/test/org/apache/solr/rest/schema/analysis/TestManagedSynonymGraphFilterFactory.java index 66e9efe5fce..778b19acaa3 100644 --- a/solr/core/src/test/org/apache/solr/rest/schema/analysis/TestManagedSynonymGraphFilterFactory.java +++ b/solr/core/src/test/org/apache/solr/rest/schema/analysis/TestManagedSynonymGraphFilterFactory.java @@ -33,7 +33,6 @@ import org.eclipse.jetty.servlet.ServletHolder; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.restlet.ext.servlet.ServerServlet; import static org.apache.solr.common.util.Utils.toJSONString; @@ -51,9 +50,6 @@ public class TestManagedSynonymGraphFilterFactory extends RestTestBase { FileUtils.copyDirectory(new File(TEST_HOME()), tmpSolrHome.getAbsoluteFile()); final SortedMap extraServlets = new TreeMap<>(); - final ServletHolder solrRestApi = new ServletHolder("SolrSchemaRestApi", ServerServlet.class); - solrRestApi.setInitParameter("org.restlet.application", "org.apache.solr.rest.SolrSchemaRestApi"); - extraServlets.put(solrRestApi, "/schema/*"); System.setProperty("managed.schema.mutable", "true"); System.setProperty("enable.update.log", "false"); diff --git a/solr/core/src/test/org/apache/solr/schema/TestCloudSchemaless.java b/solr/core/src/test/org/apache/solr/schema/TestCloudSchemaless.java index 91a6be8b9cf..09b2a6daf7c 100644 --- a/solr/core/src/test/org/apache/solr/schema/TestCloudSchemaless.java +++ b/solr/core/src/test/org/apache/solr/schema/TestCloudSchemaless.java @@ -34,7 +34,6 @@ import org.apache.solr.util.BaseTestHarness; import org.eclipse.jetty.servlet.ServletHolder; import org.junit.After; import org.junit.Test; -import org.restlet.ext.servlet.ServerServlet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -66,9 +65,6 @@ public class TestCloudSchemaless extends AbstractFullDistribZkTestBase { @Override public SortedMap getExtraServlets() { final SortedMap extraServlets = new TreeMap<>(); - final ServletHolder solrRestApi = new ServletHolder("SolrSchemaRestApi", ServerServlet.class); - solrRestApi.setInitParameter("org.restlet.application", "org.apache.solr.rest.SolrSchemaRestApi"); - extraServlets.put(solrRestApi, "/schema/*"); // '/schema/*' matches '/schema', '/schema/', and '/schema/whatever...' return extraServlets; } diff --git a/solr/licenses/org.restlet-2.4.3.jar.sha1 b/solr/licenses/org.restlet-2.4.3.jar.sha1 deleted file mode 100644 index 67a7f5c7fae..00000000000 --- a/solr/licenses/org.restlet-2.4.3.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -fb9441cfe1e17b04976bed9b0dfd8c4a39c41b78 diff --git a/solr/licenses/org.restlet-LICENSE-ASL.txt b/solr/licenses/org.restlet-LICENSE-ASL.txt deleted file mode 100644 index 261eeb9e9f8..00000000000 --- a/solr/licenses/org.restlet-LICENSE-ASL.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/solr/licenses/org.restlet-NOTICE.txt b/solr/licenses/org.restlet-NOTICE.txt deleted file mode 100644 index c7839b55efa..00000000000 --- a/solr/licenses/org.restlet-NOTICE.txt +++ /dev/null @@ -1,2 +0,0 @@ -This product includes software developed by -the Restlet project (http://www.restlet.org). \ No newline at end of file diff --git a/solr/licenses/org.restlet.ext.servlet-2.4.3.jar.sha1 b/solr/licenses/org.restlet.ext.servlet-2.4.3.jar.sha1 deleted file mode 100644 index b0aa84b827c..00000000000 --- a/solr/licenses/org.restlet.ext.servlet-2.4.3.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -5e805b9c6c07cd21958288805451236895316f56 diff --git a/solr/licenses/org.restlet.ext.servlet-LICENSE-ASL.txt b/solr/licenses/org.restlet.ext.servlet-LICENSE-ASL.txt deleted file mode 100644 index 261eeb9e9f8..00000000000 --- a/solr/licenses/org.restlet.ext.servlet-LICENSE-ASL.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/solr/licenses/org.restlet.ext.servlet-NOTICE.txt b/solr/licenses/org.restlet.ext.servlet-NOTICE.txt deleted file mode 100644 index 154ac0a6b49..00000000000 --- a/solr/licenses/org.restlet.ext.servlet-NOTICE.txt +++ /dev/null @@ -1,2 +0,0 @@ -This product includes software developed by -the SimpleXML project (http://simple.sourceforge.net). \ No newline at end of file diff --git a/solr/solrj/build.gradle b/solr/solrj/build.gradle index e8c8a072d05..7dfd3cb1847 100644 --- a/solr/solrj/build.gradle +++ b/solr/solrj/build.gradle @@ -64,7 +64,6 @@ dependencies { testImplementation ('org.eclipse.jetty:jetty-alpn-java-server', { exclude group: "org.eclipse.jetty.alpn", module: "alpn-api" }) - testImplementation 'org.restlet.jee:org.restlet.ext.servlet' testImplementation 'org.objenesis:objenesis' testImplementation('org.mockito:mockito-core', { exclude group: "net.bytebuddy", module: "byte-buddy-agent" diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/request/SchemaTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/request/SchemaTest.java index fcb10d6c75f..cb654554f51 100644 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/request/SchemaTest.java +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/request/SchemaTest.java @@ -45,7 +45,6 @@ import org.eclipse.jetty.servlet.ServletHolder; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.restlet.ext.servlet.ServerServlet; import static org.hamcrest.CoreMatchers.anyOf; import static org.hamcrest.CoreMatchers.equalTo; @@ -107,9 +106,6 @@ public class SchemaTest extends RestTestBase { FileUtils.copyDirectory(new File(getFile("solrj/solr/collection1").getParent()), tmpSolrHome.getAbsoluteFile()); final SortedMap extraServlets = new TreeMap<>(); - final ServletHolder solrRestApi = new ServletHolder("SolrSchemaRestApi", ServerServlet.class); - solrRestApi.setInitParameter("org.restlet.application", "org.apache.solr.rest.SolrSchemaRestApi"); - extraServlets.put(solrRestApi, "/schema/*"); // '/schema/*' matches '/schema', '/schema/', and '/schema/whatever...' System.setProperty("managed.schema.mutable", "true"); System.setProperty("enable.update.log", "false"); diff --git a/solr/webapp/web/WEB-INF/web.xml b/solr/webapp/web/WEB-INF/web.xml index 53ab57abbbd..2599420ddb1 100644 --- a/solr/webapp/web/WEB-INF/web.xml +++ b/solr/webapp/web/WEB-INF/web.xml @@ -47,25 +47,11 @@ org.apache.solr.servlet.LoadAdminUiServlet - - SolrRestApi - org.restlet.ext.servlet.ServerServlet - - org.restlet.application - org.apache.solr.rest.SolrSchemaRestApi - - - LoadAdminUI /index.html - - SolrRestApi - /schema/* - - .xsl diff --git a/versions.lock b/versions.lock index bb9e06acc49..7291ceac270 100644 --- a/versions.lock +++ b/versions.lock @@ -170,8 +170,6 @@ org.jdom:jdom2:2.0.6 (1 constraints: 0a05fb35) org.locationtech.spatial4j:spatial4j:0.7 (1 constraints: ab041e2c) org.ow2.asm:asm:7.2 (2 constraints: 900e3e5e) org.ow2.asm:asm-commons:7.2 (1 constraints: ad042e2c) -org.restlet.jee:org.restlet:2.4.3 (2 constraints: eb156ae7) -org.restlet.jee:org.restlet.ext.servlet:2.4.3 (1 constraints: 0b050436) org.rrd4j:rrd4j:3.5 (1 constraints: ac04252c) org.slf4j:jcl-over-slf4j:1.7.24 (1 constraints: 4005473b) org.slf4j:slf4j-api:1.7.24 (15 constraints: a3ba2a7b) diff --git a/versions.props b/versions.props index ddaf47679ef..6855cf45471 100644 --- a/versions.props +++ b/versions.props @@ -94,7 +94,6 @@ org.locationtech.spatial4j:*=0.7 org.mockito:mockito-core=2.23.4 org.objenesis:objenesis=2.6 org.ow2.asm:*=7.2 -org.restlet.jee:*=2.4.3 org.rrd4j:rrd4j=3.5 org.slf4j:*=1.7.24 org.tallison:jmatio=1.5