package org.apache.solr.core; /* * 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. */ import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; import java.nio.channels.FileChannel; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import org.apache.solr.common.SolrException; import org.apache.solr.common.util.XML; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SolrXMLSerializer { protected static Logger log = LoggerFactory .getLogger(SolrXMLSerializer.class); private final static String INDENT = " "; /** * @param w * Writer to use * @throws IOException If there is a low-level I/O error. */ void persist(Writer w, SolrXMLDef solrXMLDef) throws IOException { w.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"); w.write("<solr"); Map<String,String> rootSolrAttribs = solrXMLDef.solrAttribs; Set<String> solrAttribKeys = rootSolrAttribs.keySet(); for (String key : solrAttribKeys) { String value = rootSolrAttribs.get(key); writeAttribute(w, key, value); } w.write(">\n"); Properties containerProperties = solrXMLDef.containerProperties; if (containerProperties != null && !containerProperties.isEmpty()) { writeProperties(w, containerProperties, " "); } w.write(INDENT + "<cores"); Map<String,String> coresAttribs = solrXMLDef.coresAttribs; Set<String> coreAttribKeys = coresAttribs.keySet(); for (String key : coreAttribKeys) { String value = coresAttribs.get(key); writeAttribute(w, key, value); } w.write(">\n"); for (SolrCoreXMLDef coreDef : solrXMLDef.coresDefs) { persist(w, coreDef); } w.write(INDENT + "</cores>\n"); w.write("</solr>\n"); } /** Writes the cores configuration node for a given core. */ private void persist(Writer w, SolrCoreXMLDef coreDef) throws IOException { w.write(INDENT + INDENT + "<core"); Set<String> keys = coreDef.coreAttribs.keySet(); for (String key : keys) { writeAttribute(w, key, coreDef.coreAttribs.get(key)); } Properties properties = coreDef.coreProperties; if (properties == null || properties.isEmpty()) w.write("/>\n"); // core else { w.write(">\n"); writeProperties(w, properties, " "); w.write(INDENT + INDENT + "</core>\n"); } } private void writeProperties(Writer w, Properties props, String indent) throws IOException { for (Map.Entry<Object,Object> entry : props.entrySet()) { w.write(indent + "<property"); writeAttribute(w, "name", entry.getKey()); writeAttribute(w, "value", entry.getValue()); w.write("/>\n"); } } private void writeAttribute(Writer w, String name, Object value) throws IOException { if (value == null) return; w.write(" "); w.write(name); w.write("=\""); XML.escapeAttributeValue(value.toString(), w); w.write("\""); } void persistFile(File file, SolrXMLDef solrXMLDef) { log.info("Persisting cores config to " + file); File tmpFile = null; try { // write in temp first tmpFile = File.createTempFile("solr", ".xml", file.getParentFile()); java.io.FileOutputStream out = new java.io.FileOutputStream(tmpFile); Writer writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8")); try { persist(writer, solrXMLDef); } finally { writer.close(); out.close(); } // rename over origin or copy if this fails if (tmpFile != null) { if (tmpFile.renameTo(file)) tmpFile = null; else fileCopy(tmpFile, file); } } catch (java.io.FileNotFoundException xnf) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, xnf); } catch (java.io.IOException xio) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, xio); } finally { if (tmpFile != null) { if (!tmpFile.delete()) tmpFile.deleteOnExit(); } } } /** * Copies a src file to a dest file: used to circumvent the platform * discrepancies regarding renaming files. */ private static void fileCopy(File src, File dest) throws IOException { IOException xforward = null; FileInputStream fis = null; FileOutputStream fos = null; FileChannel fcin = null; FileChannel fcout = null; try { fis = new FileInputStream(src); fos = new FileOutputStream(dest); fcin = fis.getChannel(); fcout = fos.getChannel(); // do the file copy 32Mb at a time final int MB32 = 32 * 1024 * 1024; long size = fcin.size(); long position = 0; while (position < size) { position += fcin.transferTo(position, MB32, fcout); } } catch (IOException xio) { xforward = xio; } finally { if (fis != null) try { fis.close(); fis = null; } catch (IOException xio) {} if (fos != null) try { fos.close(); fos = null; } catch (IOException xio) {} if (fcin != null && fcin.isOpen()) try { fcin.close(); fcin = null; } catch (IOException xio) {} if (fcout != null && fcout.isOpen()) try { fcout.close(); fcout = null; } catch (IOException xio) {} } if (xforward != null) { throw xforward; } } static public class SolrXMLDef { Properties containerProperties; Map<String,String> solrAttribs; Map<String,String> coresAttribs; List<SolrCoreXMLDef> coresDefs; } static public class SolrCoreXMLDef { Properties coreProperties; Map<String,String> coreAttribs; } }