/* * 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. * * Contributions from 2013-2017 where performed either by US government * employees, or under US Veterans Health Administration contracts. * * US Veterans Health Administration contributions by government employees * are work of the U.S. Government and are not subject to copyright * protection in the United States. Portions contributed by government * employees are USGovWork (17USC ยง105). Not subject to copyright. * * Contribution by contractors to the US Veterans Health Administration * during this period are contractually contributed under the * Apache License, Version 2.0. * * See: https://www.usa.gov/government-works * * Contributions prior to 2013: * * Copyright (C) International Health Terminology Standards Development Organisation. * Licensed under the Apache License, Version 2.0. * */ package sh.isaac.api.externalizable.json; //~--- JDK imports ------------------------------------------------------------ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Semaphore; //~--- non-JDK imports -------------------------------------------------------- import org.glassfish.hk2.api.PerLookup; import org.jvnet.hk2.annotations.Service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.cedarsoftware.util.io.JsonWriter; import sh.isaac.api.component.concept.ConceptChronology; import sh.isaac.api.component.sememe.SememeChronology; import sh.isaac.api.externalizable.DataWriterService; import sh.isaac.api.externalizable.OchreExternalizable; import sh.isaac.api.util.TimeFlushBufferedOutputStream; //~--- classes ---------------------------------------------------------------- /** * {@link JsonDataWriterService} - serialize to JSON. * * @author <a href="mailto:daniel.armbrust.list@gmail.com">Dan Armbrust</a> */ @Service(name = "jsonWriter") @PerLookup public class JsonDataWriterService implements DataWriterService { /** The logger. */ private final Logger logger = LoggerFactory.getLogger(JsonDataWriterService.class); /** The pause block. */ private final Semaphore pauseBlock = new Semaphore(1); /** The json. */ private JsonWriter json; /** The fos. */ private FileOutputStream fos; /** The data path. */ private Path dataPath; //~--- constructors -------------------------------------------------------- /** * Instantiates a new json data writer service. * * @throws IOException Signals that an I/O exception has occurred. */ private JsonDataWriterService() throws IOException { // For HK2 } /** * Instantiates a new json data writer service. * * @param path the path * @throws IOException Signals that an I/O exception has occurred. */ public JsonDataWriterService(File path) throws IOException { this(); configure(path.toPath()); } /** * To support non HK2 useage. * * @param path the path * @throws IOException Signals that an I/O exception has occurred. */ public JsonDataWriterService(Path path) throws IOException { this(); configure(path); } //~--- methods ------------------------------------------------------------- /** * Close. * * @throws IOException Signals that an I/O exception has occurred. */ @Override public void close() throws IOException { try { this.json.close(); this.fos.close(); } finally { this.json = null; this.fos = null; } } /** * Configure. * * @param path the path * @throws IOException Signals that an I/O exception has occurred. */ @Override public void configure(Path path) throws IOException { if (this.json != null) { throw new IOException("Reconfiguration not supported"); } final Map<String, Object> args = new HashMap<>(); args.put(JsonWriter.PRETTY_PRINT, true); this.dataPath = path; this.fos = new FileOutputStream(path.toFile(), true); this.json = new JsonWriter(new TimeFlushBufferedOutputStream(this.fos), args); this.json.addWriter(ConceptChronology.class, new Writers.ConceptChronologyJsonWriter()); this.json.addWriter(SememeChronology.class, new Writers.SememeChronologyJsonWriter()); this.logger.info("json changeset writer has been configured to write to " + this.dataPath.toAbsolutePath().toString()); } /** * Flush. * * @throws IOException Signals that an I/O exception has occurred. * @see sh.isaac.api.externalizable.DataWriterService#flush() */ @Override public void flush() throws IOException { if (this.json != null) { this.json.flush(); } } /** * Pause. * * @throws IOException Signals that an I/O exception has occurred. */ @Override public void pause() throws IOException { if (this.json == null) { this.logger.warn("already paused!"); return; } this.pauseBlock.acquireUninterruptibly(); close(); this.logger.debug("json writer paused"); } /** * Put. * * @param ochreObject the ochre object */ @Override public void put(OchreExternalizable ochreObject) { try { this.pauseBlock.acquireUninterruptibly(); this.json.write(ochreObject); } finally { this.pauseBlock.release(); } } /** * Write out a string object to the json file - this will encode all illegal characters within the string. * Useful for writing debugging files * * @param string the string */ public void put(String string) { try { this.pauseBlock.acquireUninterruptibly(); this.json.write(string); } finally { this.pauseBlock.release(); } } /** * Resume. * * @throws IOException Signals that an I/O exception has occurred. */ @Override public void resume() throws IOException { if (this.pauseBlock.availablePermits() == 1) { this.logger.warn("asked to resume, but not paused?"); return; } if (this.json == null) { configure(this.dataPath); } this.pauseBlock.release(); this.logger.debug("json writer resumed"); } //~--- get methods --------------------------------------------------------- /** * Gets the current path. * * @return the current path */ @Override public Path getCurrentPath() { return this.dataPath; } }