/** * Licensed to The Apereo Foundation under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * * The Apereo Foundation licenses this file to you under the Educational * Community 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://opensource.org/licenses/ecl2.txt * * 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.opencastproject.search.remote; import org.opencastproject.job.api.Job; import org.opencastproject.job.api.JobParser; import org.opencastproject.mediapackage.MediaPackage; import org.opencastproject.mediapackage.MediaPackageElementFlavor; import org.opencastproject.mediapackage.MediaPackageParser; import org.opencastproject.search.api.SearchException; import org.opencastproject.search.api.SearchQuery; import org.opencastproject.search.api.SearchResult; import org.opencastproject.search.api.SearchResultImpl; import org.opencastproject.search.api.SearchService; import org.opencastproject.security.api.UnauthorizedException; import org.opencastproject.serviceregistry.api.RemoteBase; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.utils.URLEncodedUtils; import org.apache.http.message.BasicNameValuePair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; /** * A proxy to a remote search service. */ public class SearchServiceRemoteImpl extends RemoteBase implements SearchService { private static final Logger logger = LoggerFactory.getLogger(SearchServiceRemoteImpl.class); public SearchServiceRemoteImpl() { super(JOB_TYPE); } /** * {@inheritDoc} * * @see org.opencastproject.search.api.SearchService#add(org.opencastproject.mediapackage.MediaPackage) */ @Override public Job add(MediaPackage mediaPackage) throws SearchException { HttpPost post = new HttpPost("/add"); try { List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>(); params.add(new BasicNameValuePair("mediapackage", MediaPackageParser.getAsXml(mediaPackage))); post.setEntity(new UrlEncodedFormEntity(params, "UTF-8")); } catch (Exception e) { throw new SearchException("Unable to assemble a remote search request for mediapackage " + mediaPackage, e); } HttpResponse response = getResponse(post); try { if (response != null) { Job job = JobParser.parseJob(response.getEntity().getContent()); logger.info("Publishing mediapackage '{}' using a remote search service", mediaPackage.getIdentifier()); return job; } } catch (Exception e) { throw new SearchException("Unable to publish " + mediaPackage.getIdentifier() + " using a remote search service", e); } finally { closeConnection(response); } throw new SearchException("Unable to publish " + mediaPackage.getIdentifier() + " using a remote search service"); } /** * {@inheritDoc} * * @see org.opencastproject.search.api.SearchService#delete(java.lang.String) */ @Override public Job delete(String mediaPackageId) throws SearchException { HttpDelete del = new HttpDelete(mediaPackageId); HttpResponse response = getResponse(del); try { if (response != null) { Job job = JobParser.parseJob(response.getEntity().getContent()); logger.info("Removing mediapackage '{}' from a remote search service", mediaPackageId); return job; } } catch (Exception e) { throw new SearchException("Unable to remove " + mediaPackageId + " from a remote search service", e); } finally { closeConnection(response); } throw new SearchException("Unable to remove " + mediaPackageId + " from a remote search service"); } /** * {@inheritDoc} * * @see org.opencastproject.search.api.SearchService#getByQuery(org.opencastproject.search.api.SearchQuery) */ @Override public SearchResult getByQuery(SearchQuery q) throws SearchException { HttpGet get = new HttpGet(getSearchUrl(q, false)); HttpResponse response = getResponse(get); try { if (response != null) return SearchResultImpl.valueOf(response.getEntity().getContent()); } catch (Exception e) { throw new SearchException("Unable to parse results of a getByQuery request from remote search index: ", e); } finally { closeConnection(response); } throw new SearchException("Unable to perform getByQuery from remote search index"); } /** * {@inheritDoc} * * @see org.opencastproject.search.api.SearchService#getForAdministrativeRead(org.opencastproject.search.api.SearchQuery) */ @Override public SearchResult getForAdministrativeRead(SearchQuery q) throws SearchException, UnauthorizedException { HttpGet get = new HttpGet(getSearchUrl(q, true)); HttpResponse response = getResponse(get); try { if (response != null) return SearchResultImpl.valueOf(response.getEntity().getContent()); } catch (Exception e) { throw new SearchException( "Unable to parse results of a getForAdministrativeRead request from remote search index: ", e); } finally { closeConnection(response); } throw new SearchException("Unable to perform getForAdministrativeRead from remote search index"); } /** * {@inheritDoc} * * @see org.opencastproject.search.api.SearchService#getByQuery(java.lang.String, int, int) */ @Override public SearchResult getByQuery(String query, int limit, int offset) throws SearchException { List<NameValuePair> queryStringParams = new ArrayList<NameValuePair>(); queryStringParams.add(new BasicNameValuePair("q", query)); queryStringParams.add(new BasicNameValuePair("limit", Integer.toString(limit))); queryStringParams.add(new BasicNameValuePair("offset", Integer.toString(offset))); queryStringParams.add(new BasicNameValuePair("admin", Boolean.TRUE.toString())); HttpGet get = new HttpGet("/lucene.xml?" + URLEncodedUtils.format(queryStringParams, "UTF-8")); logger.debug("Sending remote query '{}'", get.getRequestLine().toString()); HttpResponse response = getResponse(get); try { if (response != null) return SearchResultImpl.valueOf(response.getEntity().getContent()); } catch (Exception e) { throw new SearchException("Unable to parse getByQuery response from remote search index", e); } finally { closeConnection(response); } throw new SearchException("Unable to perform getByQuery from remote search index"); } /** * Builds the a search URL. * * @param q * the search query * @param admin * whether this is for an administrative read * @return the search URL */ private String getSearchUrl(SearchQuery q, boolean admin) { StringBuilder url = new StringBuilder(); List<NameValuePair> queryStringParams = new ArrayList<NameValuePair>(); // MH-10216, Choose "/expisode.xml" endpoint when querying by mediapackage id (i.e. episode id ) to recieve full mp data if (q.getId() != null || q.getSeriesId() != null || q.getElementFlavors() != null || q.getElementTags() != null) { url.append("/episode.xml?"); if (q.getSeriesId() != null) queryStringParams.add(new BasicNameValuePair("sid", q.getSeriesId())); if (q.getElementFlavors() != null) { for (MediaPackageElementFlavor f : q.getElementFlavors()) { queryStringParams.add(new BasicNameValuePair("flavor", f.toString())); } } if (q.getElementTags() != null) { for (String t : q.getElementTags()) { queryStringParams.add(new BasicNameValuePair("tag", t)); } } } else { url.append("/series.xml?"); queryStringParams.add(new BasicNameValuePair("series", Boolean.toString(q.isIncludeSeries()))); queryStringParams.add(new BasicNameValuePair("episodes", Boolean.toString(q.isIncludeEpisodes()))); } // General query parameters if (q.getText() != null) queryStringParams.add(new BasicNameValuePair("q", q.getText())); if (q.getId() != null) queryStringParams.add(new BasicNameValuePair("id", q.getId())); if (admin) { queryStringParams.add(new BasicNameValuePair("admin", Boolean.TRUE.toString())); } else { queryStringParams.add(new BasicNameValuePair("admin", Boolean.FALSE.toString())); } queryStringParams.add(new BasicNameValuePair("limit", Integer.toString(q.getLimit()))); queryStringParams.add(new BasicNameValuePair("offset", Integer.toString(q.getOffset()))); url.append(URLEncodedUtils.format(queryStringParams, "UTF-8")); return url.toString(); } }