SOLR-14659: Remove restlet as dependency for the ManagedResource API (#1938)

Co-authored-by: noblepaul <noble.paul@gmail.com>
This commit is contained in:
Timothy Potter 2020-10-04 11:21:49 -06:00 committed by GitHub
parent d9a410920a
commit e879a52291
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 208 additions and 1238 deletions

View File

@ -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

View File

@ -62,36 +62,6 @@
<packageUrl regex="true">^pkg:maven/com\.google\.guava/guava@.*$</packageUrl>
<cve>CVE-2018-10237</cve>
</suppress>
<suppress>
<notes><![CDATA[
file name: org.restlet.ext.servlet-2.3.0.jar
]]></notes>
<packageUrl regex="true">^pkg:maven/org\.restlet\.jee/org\.restlet\.ext\.servlet@.*$</packageUrl>
<cpe>cpe:/a:restlet:restlet_framework</cpe>
</suppress>
<suppress>
<notes><![CDATA[
file name: org.restlet.ext.servlet-2.3.0.jar
]]></notes>
<packageUrl regex="true">^pkg:maven/org\.restlet\.jee/org\.restlet\.ext\.servlet@.*$</packageUrl>
<cpe>cpe:/a:restlet:restlet</cpe>
</suppress>
<suppress>
<notes><![CDATA[
file name: org.restlet-2.3.0.jar
We don't use class SimpleXMLProvider
]]></notes>
<packageUrl regex="true">^pkg:maven/org\.restlet\.jee/org\.restlet@.*$</packageUrl>
<cve>CVE-2017-14868</cve>
</suppress>
<suppress>
<notes><![CDATA[
file name: org.restlet-2.3.0.jar
We don't use class XmlRepresentation
]]></notes>
<packageUrl regex="true">^pkg:maven/org\.restlet\.jee/org\.restlet@.*$</packageUrl>
<cve>CVE-2017-14949</cve>
</suppress>
<suppress>
<notes><![CDATA[
file name: solr-webapp-9.0.0-SNAPSHOT.war: jquery-2.1.3.min.js

View File

@ -126,6 +126,8 @@ Other Changes
* SOLR-14036: Remove distrib=false from /terms handler's default parameters (David Smiley, Munendra S N)
* SOLR-14659: Remove restlet as dependency for the ManagedResource API (Timothy Potter, noble)
Bug Fixes
---------------------
* SOLR-14546: Fix for a relatively hard to hit issue in OverseerTaskProcessor that could lead to out of order execution

View File

@ -545,18 +545,6 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================
== Restlet Notice ==
=========================================================================
Copyright (C) 2005-2014 Restlet S.A.S.
Restlet is a registered trademark of Restlet S.A.S.
This product contains software developed by the Restlet project.
See http://www.restlet.org/
=========================================================================
== Protocol Buffers Notice ==
=========================================================================

View File

@ -27,7 +27,6 @@ dependencies {
exclude group: "net.bytebuddy", module: "byte-buddy-agent"
})
testImplementation ('org.objenesis:objenesis')
testImplementation ('org.restlet.jee:org.restlet.ext.servlet')
testImplementation project(':solr:test-framework')
}

View File

@ -44,11 +44,8 @@ import org.apache.solr.ltr.model.ModelException;
import org.apache.solr.ltr.store.FeatureStore;
import org.apache.solr.ltr.store.rest.ManagedFeatureStore;
import org.apache.solr.ltr.store.rest.ManagedModelStore;
import org.apache.solr.rest.ManagedResourceStorage;
import org.apache.solr.rest.SolrSchemaRestApi;
import org.apache.solr.util.RestTestBase;
import org.eclipse.jetty.servlet.ServletHolder;
import org.restlet.ext.servlet.ServerServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -178,17 +175,8 @@ public class TestRerankBase extends RestTestBase {
+ "/collection1/conf/schema.xml"));
}
final SortedMap<ServletHolder,String> 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<ServletHolder,String> extraServlets = new TreeMap<>();
return extraServlets;
}

View File

@ -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 }

View File

@ -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<String, String> 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;
}
}
}

View File

@ -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.
* <p>
* 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()) {
public void doInit(SolrQueryRequest solrRequest, SolrQueryResponse solrResponse) {
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();
this.solrRequest = solrRequest;
this.solrResponse = solrResponse;
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);
}
String responseWriterName = solrRequest.getParams().get(CommonParams.WT, JSON);
responseWriter = solrCore.getQueryResponseWriter(responseWriterName);
contentType = responseWriter.getContentType(solrRequest, solrResponse);
final String path = getRequest().getRootRef().getPath();
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
}
SolrCore.preDecorateResponse(solrRequest, solrResponse);
// client application can set a timeout for update requests
String updateTimeoutSecsParam = getSolrRequest().getParams().get(UPDATE_TIMEOUT_SECS);
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;
}
setExisting(false);
throw new ResourceException(t);
}
}
}
/**
* 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);
}
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, t);
}
}
@ -170,8 +103,6 @@ public abstract class BaseSolrResource extends ServerResource {
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()) {

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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 {
SolrQueryRequest req = solrRequestInfo.getReq();
RestManager restManager =
(req != null) ? req.getCore().getRestManager() : null;
final RestManager restManager;
if (restManager == null)
throw new ResourceException(Status.SERVER_ERROR_INTERNAL,
"No RestManager found!");
return restManager;
public ManagedEndpoint(RestManager restManager) {
this.restManager = 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.
*
* Determines the ManagedResource resourceId from the request path.
*/
public static class ManagedEndpoint extends BaseSolrResource
implements GETable, PUTable, POSTable, DELETEable
{
/**
* Determines the ManagedResource resourceId from the Restlet request.
*/
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,17 +280,10 @@ 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());
// supports a request for a registered resource or its child
RestManager restManager =
RestManager.getRestManager(SolrRequestInfo.getRequestInfo());
public void doInit(SolrQueryRequest solrRequest, SolrQueryResponse solrResponse) {
super.doInit(solrRequest, solrResponse);
final String resourceId = resolveResourceId(solrRequest.getPath());
managedResource = restManager.getManagedResourceOrNull(resourceId);
if (managedResource == null) {
// see if we have a registered endpoint one-level up ...
@ -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);
@ -328,11 +309,12 @@ 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,
throw new SolrException(ErrorCode.BAD_REQUEST,
"No REST managed resource registered for path "+resourceId);
}
}
@ -340,30 +322,31 @@ public class RestManager {
log.info("Found ManagedResource [{}] for {}", managedResource, resourceId);
}
@Override
public Representation put(Representation entity) {
public void delegateRequestToManagedResource() {
SolrQueryRequest req = getSolrRequest();
final String method = req.getHttpMethod();
try {
managedResource.doPut(this, entity, parseJsonFromRequestBody(entity));
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);
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() {
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();
protected Object parseJsonFromRequestBody(SolrQueryRequest req) {
Iterator<ContentStream> iter = req.getContentStreams().iterator();
if (iter.hasNext()) {
try (Reader reader = iter.next().getReader()) {
return fromJSON(reader);
} 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);
throw new SolrException(ErrorCode.SERVER_ERROR, 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);
}
return parsedJson;
throw new SolrException(ErrorCode.BAD_REQUEST, "No JSON body found in request!");
}
@Override
@ -518,14 +457,14 @@ 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<String,String> info = (Map<String,String>)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
@ -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);
@ -604,10 +543,6 @@ public class RestManager {
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.
@ -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<? extends ManagedResource> clazz) {
final ManagedResource res;
@ -666,30 +600,15 @@ 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;
}
@ -760,47 +678,4 @@ public class RestManager {
}
}
/**
* 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<String, ManagedResource> 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());
}
}
}

View File

@ -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 /&lt;context&gt;/&lt;collection&gt;/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<String> getReservedEndpoints() {
Set<String> 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;
}
}

View File

@ -16,7 +16,7 @@
*/
/**
* Solr RESTful APIs via Restlet.
* Solr RESTful APIs.
*/
package org.apache.solr.rest;

View File

@ -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<String,Object>)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!");
}

View File

@ -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<String,Object>)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!");
}

View File

@ -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;

View File

@ -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;

View File

@ -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 <requestDispatcher> allows us to handle /select with a 'qt' param
if (handler == null && parser.isHandleSelect()) {
if ("/select".equals(path) || "/select/".equals(path)) {

View File

@ -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.

View File

@ -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)) {

View File

@ -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<ServletHolder, String> 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");

View File

@ -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<ServletHolder, String> 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");

View File

@ -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<ServletHolder,String> 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);

View File

@ -19,19 +19,13 @@ 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,
@ -39,127 +33,6 @@ import org.restlet.data.Reference;
*/
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<String> 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<String> 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
* and /schema/managed. Also tests {@link ManagedWordSetResource} functionality
@ -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");
}
}

View File

@ -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<ServletHolder,String> 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);

View File

@ -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<ServletHolder,String> 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");

View File

@ -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<ServletHolder,String> 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");

View File

@ -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<ServletHolder,String> 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");

View File

@ -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<ServletHolder,String> getExtraServlets() {
final SortedMap<ServletHolder,String> 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;
}

View File

@ -1 +0,0 @@
fb9441cfe1e17b04976bed9b0dfd8c4a39c41b78

View File

@ -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.

View File

@ -1,2 +0,0 @@
This product includes software developed by
the Restlet project (http://www.restlet.org).

View File

@ -1 +0,0 @@
5e805b9c6c07cd21958288805451236895316f56

View File

@ -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.

View File

@ -1,2 +0,0 @@
This product includes software developed by
the SimpleXML project (http://simple.sourceforge.net).

View File

@ -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"

View File

@ -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<ServletHolder, String> 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");

View File

@ -47,25 +47,11 @@
<servlet-class>org.apache.solr.servlet.LoadAdminUiServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>SolrRestApi</servlet-name>
<servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class>
<init-param>
<param-name>org.restlet.application</param-name>
<param-value>org.apache.solr.rest.SolrSchemaRestApi</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>LoadAdminUI</servlet-name>
<url-pattern>/index.html</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>SolrRestApi</servlet-name>
<url-pattern>/schema/*</url-pattern>
</servlet-mapping>
<mime-mapping>
<extension>.xsl</extension>
<!-- per http://www.w3.org/TR/2006/PR-xslt20-20061121/ -->

View File

@ -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)

View File

@ -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