// // OMEWriter.java // /* OME database I/O package for communicating with OME and OMERO servers. Copyright (C) 2005-@year@ Melissa Linkert, Curtis Rueden and Philip Huettl. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package loci.ome.io; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.util.Hashtable; import loci.common.DateTools; import loci.common.ReflectException; import loci.common.ReflectedUniverse; import loci.common.services.DependencyException; import loci.common.services.ServiceException; import loci.common.services.ServiceFactory; import loci.common.xml.XMLTools; import loci.formats.FileStitcher; import loci.formats.FormatException; import loci.formats.FormatTools; import loci.formats.FormatWriter; import loci.formats.ImageTools; import loci.formats.meta.MetadataRetrieve; import loci.formats.services.OMEXMLService; import org.apache.log4j.ConsoleAppender; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.PatternLayout; /** * Uploads images to an OME server. * * <dl><dt><b>Source code:</b></dt> * <dd><a href="http://trac.openmicroscopy.org.uk/ome/browser/bioformats.git/components/ome-io/src/loci/ome/io/OMEWriter.java">Trac</a>, * <a href="http://git.openmicroscopy.org/?p=bioformats.git;a=blob;f=components/ome-io/src/loci/ome/io/OMEWriter.java;hb=HEAD">Gitweb</a></dd></dl> */ public class OMEWriter extends FormatWriter { // -- Static fields -- private static boolean hasOMEJava = true; private static ReflectedUniverse r = createReflectedUniverse(); private static ReflectedUniverse createReflectedUniverse() { r = null; try { r = new ReflectedUniverse(); r.exec("import java.lang.Class"); r.exec("import org.openmicroscopy.ds.DataFactory"); r.exec("import org.openmicroscopy.ds.DataServer"); r.exec("import org.openmicroscopy.ds.DataServices"); r.exec("import org.openmicroscopy.ds.FieldsSpecification"); r.exec("import org.openmicroscopy.ds.RemoteCaller"); r.exec("import org.openmicroscopy.ds.dto.ModuleExecution"); r.exec("import org.openmicroscopy.ds.dto.UserState"); r.exec("import org.openmicroscopy.ds.managers.ImportManager"); r.exec("import org.openmicroscopy.ds.st.Experimenter"); r.exec("import org.openmicroscopy.ds.st.LogicalChannel"); r.exec("import org.openmicroscopy.ds.st.Pixels"); r.exec("import org.openmicroscopy.ds.st.Repository"); r.exec("import org.openmicroscopy.is.CompositingSettings"); r.exec("import org.openmicroscopy.is.ImageServer"); r.exec("import org.openmicroscopy.is.PixelsFactory"); } catch (ReflectException e) { LOGGER.debug(OMEUtils.NO_OME_MSG, e); hasOMEJava = false; } return r; } // -- Fields -- /** Authentication credentials. */ private OMECredentials credentials; /** Image server. */ private String omeis; /** Number of planes written. */ private int planesWritten = 0; private String[] originalFiles; // -- Constructor -- public OMEWriter() { super("Open Microscopy Environment", ""); } // -- IFormatWriter API methods -- /** * @see loci.formats.IFormatWriter#saveBytes(int, byte[], int, int, int, int) */ public void saveBytes(int no, byte[] bytes, int x, int y, int w, int h) throws FormatException, IOException { if (!hasOMEJava) throw new FormatException(OMEUtils.NO_OME_MSG); if (currentId != null && credentials == null) { // parse the ID string to get the server, user name and password credentials = new OMECredentials(currentId); login(); credentials.imageID = -1; // initialize necessary services try { r.setVar("DATA_FACTORY_CLASS", "org.openmicroscopy.ds.DataFactory"); r.exec("DATA_FACTORY_CLASS = Class.forName(DATA_FACTORY_CLASS)"); r.setVar("PIXELS_FACTORY_CLASS", "org.openmicroscopy.is.PixelsFactory"); r.exec("PIXELS_FACTORY_CLASS = Class.forName(PIXELS_FACTORY_CLASS)"); r.setVar("IMPORT_MANAGER_CLASS", "org.openmicroscopy.ds.managers.ImportManager"); r.exec("IMPORT_MANAGER_CLASS = Class.forName(IMPORT_MANAGER_CLASS)"); r.exec("df = rs.getService(DATA_FACTORY_CLASS)"); r.exec("im = rs.getService(IMPORT_MANAGER_CLASS)"); r.exec("pf = rs.getService(PIXELS_FACTORY_CLASS)"); r.setVar("ID", "id"); r.setVar("EXPERIMENTER", "experimenter"); r.exec("fields = new FieldsSpecification()"); r.exec("fields.addWantedField(ID)"); r.exec("fields.addWantedField(EXPERIMENTER)"); r.exec("fields.addWantedField(EXPERIMENTER, ID)"); r.exec("userState = df.getUserState(fields)"); r.exec("exp = userState.getExperimenter()"); r.setVar("zero", 0l); r.setVar("omeis", omeis); r.exec("repository = pf.findRepository(zero)"); r.exec("repository.setImageServerURL(omeis)"); } catch (ReflectException e) { throw new FormatException(e); } if (metadataRetrieve == null) { throw new FormatException("Metadata store not specified."); } } try { r.exec("im.startImport(exp)"); r.setVar("IMAGE_CLASS", "org.openmicroscopy.ds.dto.Image"); r.exec("IMAGE_CLASS = Class.forName(IMAGE_CLASS)"); r.exec("img = df.createNew(IMAGE_CLASS)"); // upload original files if (originalFiles != null) { r.exec("of = im.getOriginalFilesMEX()"); for (int i=0; i<originalFiles.length; i++) { r.setVar("file", new File(originalFiles[i])); r.exec("ofile = pf.uploadFile(repository, of, file)"); } r.exec("df.updateMarked()"); r.exec("of.setImage(img)"); } } catch (ReflectException e) { LOGGER.debug("Original file upload failed", e); } int sizeX = metadataRetrieve.getPixelsSizeX(series).getValue().intValue(); int sizeY = metadataRetrieve.getPixelsSizeY(series).getValue().intValue(); int z = metadataRetrieve.getPixelsSizeZ(series).getValue().intValue(); int c = metadataRetrieve.getPixelsSizeC(series).getValue().intValue(); int t = metadataRetrieve.getPixelsSizeT(series).getValue().intValue(); String order = metadataRetrieve.getPixelsDimensionOrder(series).toString(); String pixelTypeString = metadataRetrieve.getPixelsType(series).toString(); int pixelType = FormatTools.pixelTypeFromString(pixelTypeString); int bpp = FormatTools.getBytesPerPixel(pixelType); boolean bigEndian = metadataRetrieve.getPixelsBinDataBigEndian(series, 0).booleanValue(); try { r.exec("sessionKey = rc.getSessionKey()"); r.exec("is = ImageServer.getHTTPImageServer(omeis, sessionKey)"); if (credentials.imageID == -1) { r.setVar("x", sizeX); r.setVar("y", sizeY); r.setVar("z", z); r.setVar("c", c); r.setVar("t", t); r.setVar("bpp", bpp); r.setVar("bigEndian", bigEndian); r.setVar("float", pixelTypeString.equals("float")); r.setVar("pixelType", pixelTypeString); r.exec("pixelsId = is.newPixels(x, y, z, c, t, bpp, bigEndian, float)"); credentials.imageID = ((Long) r.getVar("pixelsId")).longValue(); } } catch (ReflectException e) { throw new FormatException(e); } try { int planeLength = sizeX * sizeY * bpp; int nChannels = bytes.length / planeLength; for (int ch=0; ch<nChannels; ch++) { int[] coords = FormatTools.getZCTCoords(order, z, c, t, z*c*t, planesWritten); byte[] b = ImageTools.splitChannels(bytes, ch, nChannels, bpp, false, true); r.setVar("zndx", coords[0]); r.setVar("cndx", coords[1]); r.setVar("tndx", coords[2]); r.setVar("bytes", b); r.setVar("bigEndian", bigEndian); r.setVar("pixelsId", credentials.imageID); r.exec("is.setPlane(pixelsId, zndx, cndx, tndx, bytes, bigEndian)"); planesWritten++; } } catch (ReflectException e) { throw new FormatException("Failed to upload plane.", e); } if (series == metadataRetrieve.getImageCount() - 1) { try { r.exec("pixelsId = is.finishPixels(pixelsId)"); credentials.imageID = ((Long) r.getVar("pixelsId")).longValue(); r.setVar("NOW", "now"); String creationDate = metadataRetrieve.getImageAcquiredDate(series); if (creationDate == null) { creationDate = DateTools.convertDate(System.currentTimeMillis(), DateTools.UNIX); } r.setVar("creationDate", creationDate); if (metadataRetrieve.getImageName(series) != null) { r.setVar("imageName", metadataRetrieve.getImageName(series)); } else r.setVar("imageName", "new image " + credentials.imageID); r.setVar("imageDescription", metadataRetrieve.getImageDescription(series)); r.exec("img.setOwner(exp)"); r.exec("img.setInserted(NOW)"); r.exec("img.setCreated(creationDate)"); r.exec("img.setName(imageName)"); r.exec("img.setDescription(imageDescription)"); r.exec("df.update(img)"); r.exec("ii = im.getImageImportMEX(img)"); r.exec("ii.setExperimenter(exp)"); r.exec("df.updateMarked()"); r.exec("df.update(ii)"); r.setVar("PIXELS", "Pixels"); r.exec("pixels = df.createNew(PIXELS)"); r.exec("pixels.setRepository(repository)"); r.exec("pixels.setImage(img)"); r.exec("pixels.setModuleExecution(ii)"); r.setVar("pixelsIdObj", new Long(credentials.imageID)); r.exec("pixels.setImageServerID(pixelsIdObj)"); r.exec("pixels.setSizeX(x)"); r.exec("pixels.setSizeY(y)"); r.exec("pixels.setSizeZ(z)"); r.exec("pixels.setSizeC(c)"); r.exec("pixels.setSizeT(t)"); r.exec("pixels.setPixelType(pixelType)"); r.exec("settings = " + "CompositingSettings.createDefaultPGISettings(z, c, t)"); r.exec("pf.setThumbnail(pixels, settings)"); r.exec("df.update(pixels)"); r.setVar("GRAY", "Gray 00"); r.setVar("LOGICAL_CHANNEL", "LogicalChannel"); r.setVar("PHOTOMETRIC_INTERPRETATION", "monochrome"); r.exec("logical = df.createNew(LOGICAL_CHANNEL)"); r.exec("logical.setImage(img)"); r.exec("logical.setModuleExecution(ii)"); r.exec("logical.setFluor(GRAY)"); r.exec("logical.setPhotometricInterpretation(" + "PHOTOMETRIC_INTERPRETATION)"); r.exec("df.update(logical)"); r.setVar("PIXEL_CHANNEL_COMPONENT", "PixelChannelComponent"); r.setVar("zeroObj", new Integer(0)); r.exec("physical = df.createNew(PIXEL_CHANNEL_COMPONENT)"); r.exec("physical.setImage(img)"); r.exec("physical.setPixels(pixels)"); r.exec("physical.setIndex(zeroObj)"); r.exec("physical.setLogicalChannel(logical)"); r.exec("physical.setModuleExecution(ii)"); r.exec("df.update(physical)"); // upload original metadata, if available boolean isOMEXML = false; try { ServiceFactory factory = new ServiceFactory(); OMEXMLService service = factory.getInstance(OMEXMLService.class); isOMEXML = service.isOMEXMLMetadata(metadataRetrieve); } catch (DependencyException e) { LOGGER.warn("OMEXMLService not available", e); } if (isOMEXML) { r.setVar("metadata", metadataRetrieve); Hashtable meta = (Hashtable) r.exec("metadata.getOriginalMetadata()"); String[] keys = (String[]) meta.keySet().toArray(new String[0]); r.setVar("ORIGINAL_METADATA", "OriginalMetadata"); r.setVar("NAME", "Name"); r.setVar("VALUE", "Value"); for (int i=0; i<keys.length; i++) { r.exec("attribute = df.createNew(ORIGINAL_METADATA)"); r.setVar("K", XMLTools.sanitizeXML(keys[i])); r.setVar("V", XMLTools.sanitizeXML((String) meta.get(keys[i]))); r.exec("attribute.setStringElement(NAME, K)"); r.exec("attribute.setStringElement(VALUE, V)"); r.exec("attribute.setImage(img)"); r.exec("attribute.setModuleExecution(ii)"); r.exec("df.update(attribute)"); } } r.setVar("FINISHED", "FINISHED"); if (originalFiles != null) { r.exec("of.setStatus(FINISHED)"); r.exec("df.update(of)"); } r.exec("ii.setStatus(FINISHED)"); r.exec("df.update(ii)"); r.exec("img.setDefaultPixels(pixels)"); r.exec("df.update(img)"); r.exec("im.finishImport()"); } catch (ReflectException e) { throw new FormatException(e); } planesWritten = 0; credentials.imageID = -1; } } /* @see loci.formats.IFormatWriter#canDoStacks(String) */ @Override public boolean canDoStacks() { return true; } // -- IFormatHandler API methods -- /* @see loci.formats.IFormatHandler#close() */ @Override public void close() throws IOException { try { r.exec("rc.logout()"); } catch (ReflectException e) { } credentials = null; planesWritten = 0; if (currentId != null) metadataRetrieve = null; currentId = null; } // -- Helper methods -- private void login() throws FormatException { while (credentials.server.lastIndexOf("/") > 7) { int slash = credentials.server.lastIndexOf("/"); credentials.server = credentials.server.substring(0, slash); } omeis = credentials.server + "/cgi-bin/omeis"; credentials.server += "/shoola"; if (!credentials.server.startsWith("http://")) { credentials.server = "http://" + credentials.server; omeis = "http://" + omeis; } LOGGER.info("Logging in to {}", credentials.server); try { r.setVar("server", credentials.server); r.setVar("user", credentials.username); r.setVar("pass", credentials.password); r.exec("rs = DataServer.getDefaultServices(server)"); r.exec("rc = rs.getRemoteCaller()"); r.exec("rc.login(user, pass)"); } catch (ReflectException e) { throw new FormatException("Login failed", e); } } // -- OMEWriter API methods -- public void setOriginalFiles(String[] filenames) { originalFiles = filenames; } // -- Main method -- public static void main(String[] args) throws Exception { Logger root = Logger.getRootLogger(); root.setLevel(Level.INFO); root.addAppender(new ConsoleAppender(new PatternLayout("%m%n"))); String server = null, user = null, pass = null; String id = null; int series = -1; // parse command-line arguments boolean doUsage = false; if (args.length == 0) doUsage = true; for (int i=0; i<args.length; i++) { if (args[i].startsWith("-")) { // argument is a command line flag String param = args[i]; try { if (param.equalsIgnoreCase("-s")) server = args[++i]; else if (param.equalsIgnoreCase("-u")) user = args[++i]; else if (param.equalsIgnoreCase("-p")) pass = args[++i]; else if (param.equalsIgnoreCase("-series")) { series = Integer.parseInt(args[++i]); } else if (param.equalsIgnoreCase("-h") || param.equalsIgnoreCase("-?")) { doUsage = true; } else { LOGGER.warn("Unknown flag: {}", param); doUsage = true; break; } } catch (ArrayIndexOutOfBoundsException exc) { if (i == args.length - 1) { LOGGER.warn( "Flag {} must be followed by a parameter value.", param); doUsage = true; break; } else throw exc; } } else { if (id == null) id = args[i]; else { LOGGER.warn("Unknown argument: {}", args[i]); } } } if (id == null) doUsage = true; if (doUsage) { LOGGER.info("Usage: omeul [-s server.address] " + "[-u username] [-p password] [-series series.number] filename"); System.exit(1); } // ask for information if necessary BufferedReader cin = new BufferedReader(new InputStreamReader(System.in)); if (server == null) { LOGGER.info("Server address? "); try { server = cin.readLine(); } catch (IOException exc) { } } if (user == null) { LOGGER.info("Username? "); try { user = cin.readLine(); } catch (IOException exc) { } } if (pass == null) { LOGGER.info("Password? "); try { pass = cin.readLine(); } catch (IOException exc) { } } if (server == null || user == null || pass == null) { LOGGER.error("Could not obtain server login information"); System.exit(2); } LOGGER.info("Using server {} as user {}", server, user); // create image uploader OMEWriter uploader = new OMEWriter(); FileStitcher reader = new FileStitcher(); reader.setOriginalMetadataPopulated(true); try { ServiceFactory factory = new ServiceFactory(); OMEXMLService service = factory.getInstance(OMEXMLService.class); reader.setMetadataStore(service.createOMEXMLMetadata()); } catch (DependencyException e) { LOGGER.warn("OMEXMLService not available", e); } catch (ServiceException e) { LOGGER.warn("Could not parse OME-XML", e); } reader.setId(id); uploader.setMetadataRetrieve((MetadataRetrieve) reader.getMetadataStore()); uploader.setOriginalFiles(reader.getUsedFiles()); uploader.setId(server + "?user=" + user + "&password=" + pass); int start = series == -1 ? 0 : series; int end = series == -1 ? reader.getSeriesCount() : series + 1; for (int s=start; s<end; s++) { reader.setSeries(s); uploader.setSeries(s); for (int i=0; i<reader.getImageCount(); i++) { uploader.saveBytes(i, reader.openBytes(i)); } } reader.close(); uploader.close(); } }