/* * 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.client.solrj.util; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.Map; import java.util.Map.Entry; import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.SolrInputField; import org.apache.solr.common.cloud.Slice; import org.apache.solr.common.util.Base64; import org.apache.solr.common.util.ContentStream; import org.apache.solr.common.util.ContentStreamBase; import org.apache.solr.common.util.XML; /** * * @since solr 1.3 */ public class ClientUtils { // Standard Content types public static final String TEXT_XML = "application/xml; charset=UTF-8"; /** * Take a string and make it an iterable ContentStream */ public static Collection<ContentStream> toContentStreams( final String str, final String contentType ) { if( str == null ) return null; ArrayList<ContentStream> streams = new ArrayList<>( 1 ); ContentStreamBase ccc = new ContentStreamBase.StringStream( str ); ccc.setContentType( contentType ); streams.add( ccc ); return streams; } //------------------------------------------------------------------------ //------------------------------------------------------------------------ public static void writeXML( SolrInputDocument doc, Writer writer ) throws IOException { writer.write("<doc>"); for( SolrInputField field : doc ) { String name = field.getName(); for( Object v : field ) { String update = null; if (v instanceof Map) { // currently only supports a single value for (Entry<Object,Object> entry : ((Map<Object,Object>)v).entrySet()) { update = entry.getKey().toString(); v = entry.getValue(); if (v instanceof Collection) { Collection values = (Collection) v; for (Object value : values) { writeVal(writer, name, value, update); } } else { writeVal(writer, name, v, update); } } } else { writeVal(writer, name, v, update); } } } if (doc.hasChildDocuments()) { for (SolrInputDocument childDocument : doc.getChildDocuments()) { writeXML(childDocument, writer); } } writer.write("</doc>"); } private static void writeVal(Writer writer, String name, Object v, String update) throws IOException { if (v instanceof Date) { v = ((Date)v).toInstant().toString(); } else if (v instanceof byte[]) { byte[] bytes = (byte[]) v; v = Base64.byteArrayToBase64(bytes, 0, bytes.length); } else if (v instanceof ByteBuffer) { ByteBuffer bytes = (ByteBuffer) v; v = Base64.byteArrayToBase64(bytes.array(), bytes.position(),bytes.limit() - bytes.position()); } if (update == null) { if (v != null) { XML.writeXML(writer, "field", v.toString(), "name", name ); } } else { if (v == null) { XML.writeXML(writer, "field", null, "name", name, "update", update, "null", true); } else { XML.writeXML(writer, "field", v.toString(), "name", name, "update", update); } } } public static String toXML( SolrInputDocument doc ) { StringWriter str = new StringWriter(); try { writeXML( doc, str ); } catch( Exception ex ){} return str.toString(); } //--------------------------------------------------------------------------------------- /** * See: <a href="https://www.google.com/?gws_rd=ssl#q=lucene+query+parser+syntax">Lucene query parser syntax</a> * for more information on Escaping Special Characters */ // NOTE: its broken to link to any lucene-queryparser.jar docs, not in classpath!!!!! public static String escapeQueryChars(String s) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); // These characters are part of the query syntax and must be escaped if (c == '\\' || c == '+' || c == '-' || c == '!' || c == '(' || c == ')' || c == ':' || c == '^' || c == '[' || c == ']' || c == '\"' || c == '{' || c == '}' || c == '~' || c == '*' || c == '?' || c == '|' || c == '&' || c == ';' || c == '/' || Character.isWhitespace(c)) { sb.append('\\'); } sb.append(c); } return sb.toString(); } /** * Returns the value encoded properly so it can be appended after a <pre>name=</pre> local-param. */ public static String encodeLocalParamVal(String val) { int len = val.length(); int i = 0; if (len > 0 && val.charAt(0) != '$') { for (;i<len; i++) { char ch = val.charAt(i); if (Character.isWhitespace(ch) || ch=='}') break; } } if (i>=len) return val; // We need to enclose in quotes... but now we need to escape StringBuilder sb = new StringBuilder(val.length() + 4); sb.append('\''); for (i=0; i<len; i++) { char ch = val.charAt(i); if (ch=='\'') { sb.append('\\'); } sb.append(ch); } sb.append('\''); return sb.toString(); } /** Constructs a slices map from a collection of slices and handles disambiguation if multiple collections are being queried simultaneously */ public static void addSlices(Map<String,Slice> target, String collectionName, Collection<Slice> slices, boolean multiCollection) { for (Slice slice : slices) { String key = slice.getName(); if (multiCollection) key = collectionName + "_" + key; target.put(key, slice); } } }