Java tutorial
/* * The Gemma project * * Copyright (c) 2009 University of British Columbia * * 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. * */ package ubic.gemma.image.aba; import java.io.DataInputStream; import java.io.EOFException; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.Collection; import java.util.HashSet; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.stereotype.Component; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import ubic.gemma.loader.entrez.pubmed.XMLUtils; import ubic.gemma.util.ConfigUtils; /** * Acts as a convenient front end to the Allen Brain Atlas REST (web) services Used the ABAapi.java as the original * template for this Service (found in ABA demo code). For the most current API regarding these methods go to: * http://community.brain-map.org/confluence/display/DataAPI/Home NO AJAX Methods directly exposed by this service. * * @author kelsey * @version $Id: AllenBrainAtlasServiceImpl.java,v 1.1 2012/03/12 05:03:46 paul Exp $ */ @Component public class AllenBrainAtlasServiceImpl implements AllenBrainAtlasService { private static final String ABA_CACHE = "/abaCache/"; private static Log log = LogFactory.getLog(AllenBrainAtlasServiceImpl.class.getName()); protected PrintStream infoOut; protected PrintStream errOut; protected boolean verbose; protected boolean useFileCache; protected String cacheDir; public AllenBrainAtlasServiceImpl() { initDefaults(); } /** * Given a predefined URL (one of the constants declared in the AllenBrainAtlasService) and a list of arguments will * return the correct REST URL for the desired method call * * @param urlPattern * @param args * @return */ protected String buildUrlString(String urlPattern, String args[]) { for (int i = 0; i < args.length; i++) urlPattern = urlPattern.replaceFirst("@", args[i]); return (API_BASE_URL + urlPattern); } /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#getAtlasImageMap(java.lang.Integer) */ @Override public Document getAtlasImageMap(Integer imageseriesId) { File outputFile = getFile("atlasImageMap" + imageseriesId.toString()); Document atlasImageMapDoc = null; try { FileOutputStream out = new FileOutputStream(outputFile); this.getAtlasImageMap(imageseriesId, out); atlasImageMapDoc = XMLUtils.openAndParse(new FileInputStream(outputFile)); } catch (ParserConfigurationException pce) { log.error(pce); return null; } catch (SAXException se) { log.error(se); } catch (FileNotFoundException fnfe) { log.error(fnfe); } catch (IOException io) { } return atlasImageMapDoc; } /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#getAtlasImageMap(java.lang.Integer, java.io.OutputStream) */ @Override public boolean getAtlasImageMap(Integer imageseriesid, OutputStream out) throws MalformedURLException, IOException { String args[] = { imageseriesid.toString() }; String getImageMapUrl = buildUrlString(GET_ATLAS_IMAGE_MAP_URL, args); return (doPageDownload(getImageMapUrl, out)); } /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#getAtlasInfo(java.lang.String, java.io.OutputStream) */ @Override public boolean getAtlasInfo(String plane, OutputStream out) throws MalformedURLException, IOException { String args[] = { plane }; String getAtlasInfoUrl = buildUrlString(GET_ATLAS_INFO_URL, args); return (doPageDownload(getAtlasInfoUrl, out)); } /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#getCacheDir() */ @Override public String getCacheDir() { return (this.cacheDir); } /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#getCaching() */ @Override public boolean getCaching() { return (this.useFileCache); } /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#getErrOut() */ @Override public PrintStream getErrOut() { return (this.errOut); } /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#getExpressionInfo(java.lang.Integer, java.io.OutputStream) */ @Override public boolean getExpressionInfo(Integer imageseriesId, OutputStream out) throws MalformedURLException, IOException { String args[] = { imageseriesId.toString() }; String getExpressionInfoUrl = buildUrlString(GET_EXPRESSION_INFO_URL, args); return (doPageDownload(getExpressionInfoUrl, out)); } /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#getExpressionVolume(java.lang.Integer, java.io.OutputStream) */ @Override public boolean getExpressionVolume(Integer imageseriesId, OutputStream out) throws MalformedURLException, IOException { String args[] = { imageseriesId.toString() }; String getVolumeUrl = buildUrlString(GET_EXPRESSION_VOLUME_URL, args); return (doPageDownload(getVolumeUrl, out)); } /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#getGene(java.lang.String) */ @Override public AbaGene getGene(String givenGene) throws IOException { AbaGene result = getGene(givenGene, false); if (result == null) { result = getGene(givenGene, true); } if (result == null) { log.info(givenGene + " not found in aba"); } return result; } /** * Given a gene too look for for will return the coressponding abaGene (useful for finding images) * * @param givenGene symbol of gene that will be used to search ABA. * @return */ protected AbaGene getGene(String givenGene, boolean correctCase) throws IOException { String gene = givenGene; if (correctCase) { gene = correctCase(gene); } File outputFile = getFile(gene); Document geneDoc = null; try { FileOutputStream out = new FileOutputStream(outputFile); this.getGene(gene, out); out.close(); geneDoc = XMLUtils.openAndParse(new FileInputStream(outputFile)); } catch (ParserConfigurationException pce) { log.warn(pce); return null; } catch (SAXException se) { log.warn(se); } catch (FileNotFoundException fnfe) { return null; } if (geneDoc == null) { return null; } Collection<String> xmlData = XMLUtils.extractTagData(geneDoc, "geneid"); Integer geneId = xmlData.isEmpty() ? null : Integer.parseInt(xmlData.iterator().next()); xmlData = XMLUtils.extractTagData(geneDoc, "genename"); String geneName = xmlData.isEmpty() ? null : xmlData.iterator().next(); xmlData = XMLUtils.extractTagData(geneDoc, "genesymbol"); String geneSymbol = xmlData.isEmpty() ? null : xmlData.iterator().next(); xmlData = XMLUtils.extractTagData(geneDoc, "entrezgeneid"); Integer entrezGeneId = xmlData.isEmpty() ? null : Integer.parseInt(xmlData.iterator().next()); xmlData = XMLUtils.extractTagData(geneDoc, "ncbiaccessionnumber"); String ncbiAccessionNumber = xmlData.isEmpty() ? null : xmlData.iterator().next(); String geneUrl = (geneSymbol == null) ? null : this.getGeneUrl(geneSymbol); if (geneId == null && geneSymbol == null) return null; AbaGene geneData = new AbaGene(geneId, geneSymbol, geneName, entrezGeneId, ncbiAccessionNumber, geneUrl, null); NodeList idList = geneDoc.getChildNodes().item(0).getChildNodes(); // log.debug( "Got " + idList.getLength() ); for (int i = 0; i < idList.getLength(); i++) { Node item = idList.item(i); if (!item.getNodeName().equals("image-series")) continue; NodeList imageSeriesList = item.getChildNodes(); for (int j = 0; j < imageSeriesList.getLength(); j++) { Node imageSeries = imageSeriesList.item(j); NodeList childNodes = imageSeries.getChildNodes(); Integer imageSeriesId = null; String plane = null; for (int m = 0; m < childNodes.getLength(); m++) { Node c = childNodes.item(m); // log.info( c.getNodeName() ); String n = c.getNodeName(); try { if (n.equals("imageseriesid")) { imageSeriesId = Integer.parseInt(XMLUtils.getTextValue((Element) c)); } else if (n.equals("plane")) { plane = XMLUtils.getTextValue((Element) c); } else { // Just skip and check the next one. } } catch (IOException ioe) { log.warn(ioe); } } if (imageSeriesId != null && plane != null) { ImageSeries is = new ImageSeries(imageSeriesId, plane); geneData.addImageSeries(is); log.debug("added image series to gene data"); } else { log.debug("Skipping adding imageSeries to gene cause data missing"); } } } return geneData; } /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#getGeneUrl(java.lang.String) */ @Override public String getGeneUrl(String gene) { return HTML_GENE_DETAILS_URL.replaceFirst("@", this.correctCase(gene)); } /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#getImageROI(java.lang.String, java.lang.Integer, * java.lang.Integer, java.lang.Integer, java.lang.Integer, java.lang.Integer, java.lang.Integer, * java.io.OutputStream) */ @Override public boolean getImageROI(String imagePath, Integer zoom, Integer top, Integer left, Integer width, Integer height, Integer mimeType, OutputStream out) throws MalformedURLException, IOException { String args[] = { mimeType.toString(), zoom.toString(), top.toString(), left.toString(), width.toString(), height.toString(), imagePath }; String getImageUrl = buildUrlString(GET_IMAGE_ROI_URL, args); return (doPageDownload(getImageUrl, out)); } /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#getImageseries(java.lang.Integer) */ @Override public Collection<Image> getImageseries(Integer imageseriesId) { File outputFile = getFile("ImageseriesId_" + imageseriesId.toString()); Document imageSeriesDoc = null; try { FileOutputStream out = new FileOutputStream(outputFile); this.getImageseries(imageseriesId, out); imageSeriesDoc = XMLUtils.openAndParse(new FileInputStream(outputFile)); } catch (Exception e) { log.error(e.getMessage(), e.getCause()); return null; } NodeList idList = imageSeriesDoc.getChildNodes().item(0).getChildNodes(); Collection<Image> results = new HashSet<Image>(); for (int i = 0; i < idList.getLength(); i++) { Node item = idList.item(i); if (!item.getNodeName().equals("images")) continue; NodeList imageList = item.getChildNodes(); for (int j = 0; j < imageList.getLength(); j++) { Node image = imageList.item(j); if (!image.getNodeName().equals("image")) continue; NodeList childNodes = image.getChildNodes(); Integer imageId = null; String displayName = null; Integer position = null; Integer referenceAtlasIndex = null; String thumbnailUrl = null; String zoomifiedNisslUrl = null; String expressionThumbnailUrl = null; String downloadImagePath = null; String downloadExpressionPath = null; for (int m = 0; m < childNodes.getLength(); m++) { Node c = childNodes.item(m); // log.info( c.getNodeName() ); String n = c.getNodeName(); try { if (n.equals("#text")) { continue; // added to make faster as half of comparisions are empty nodes of this type! } else if (n.equals("imageid")) { imageId = Integer.parseInt(XMLUtils.getTextValue((Element) c)); } else if (n.equals("imagedisplayname")) { displayName = XMLUtils.getTextValue((Element) c); } else if (n.equals("position")) { position = Integer.parseInt(XMLUtils.getTextValue((Element) c)); } else if (n.equals("referenceatlasindex")) { referenceAtlasIndex = Integer.parseInt(XMLUtils.getTextValue((Element) c)); } else if (n.equals("thumbnailurl")) { thumbnailUrl = XMLUtils.getTextValue((Element) c); } else if (n.equals("zoomifiednisslurl")) { zoomifiedNisslUrl = XMLUtils.getTextValue((Element) c); } else if (n.equals("expressthumbnailurl")) { expressionThumbnailUrl = XMLUtils.getTextValue((Element) c); } else if (n.equals("downloadImagePath")) { downloadImagePath = XMLUtils.getTextValue((Element) c); } else if (n.equals("downloadExpressionPath")) { downloadExpressionPath = XMLUtils.getTextValue((Element) c); } else { continue; } } catch (IOException ioe) { log.warn(ioe); } } // for loop if (imageId != null && downloadImagePath != null) { Image img = new Image(displayName, imageId, position, referenceAtlasIndex, thumbnailUrl, zoomifiedNisslUrl, expressionThumbnailUrl, downloadImagePath, downloadExpressionPath, 0, 0); results.add(img); } else { log.info( "Skipping adding image to collection cause necessary data missing after parsing image xml"); } } } return results; } /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#getImagesFromImageSeries(java.util.Collection) */ @Override public Collection<Image> getImagesFromImageSeries(Collection<ImageSeries> imageSeries) { Collection<Image> representativeImages = new HashSet<Image>(); if (imageSeries != null) { for (ImageSeries is : imageSeries) { if (is.getImages() == null) continue; for (Image img : is.getImages()) { // Convert the urls into fully qualified ones for ez displaying String args[] = { "2", "2", img.getDownloadExpressionPath() }; img.setDownloadExpressionPath(this.buildUrlString(AllenBrainAtlasService.GET_IMAGE_URL, args)); img.setExpressionThumbnailUrl( AllenBrainAtlasService.API_BASE_URL + img.getExpressionThumbnailUrl()); representativeImages.add(img); } } } return representativeImages; } /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#getInfoOut() */ @Override public PrintStream getInfoOut() { return (this.infoOut); } /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#getRepresentativeSaggitalImages(java.lang.String) */ @Override public Collection<ImageSeries> getRepresentativeSaggitalImages(String gene) throws IOException { AbaGene grin1 = this.getGene(gene); if (grin1 == null) return null; Collection<ImageSeries> representativeSaggitalImages = new HashSet<ImageSeries>(); for (ImageSeries is : grin1.getImageSeries()) { if (is.getPlane().equalsIgnoreCase("sagittal")) { Collection<Image> images = this.getImageseries(is.getImageSeriesId()); Collection<Image> representativeImages = new HashSet<Image>(); for (Image img : images) { if ((2600 > img.getPosition()) && (img.getPosition() > 2200)) { representativeImages.add(img); } } if (representativeImages.isEmpty()) continue; // Only add if there is something to add is.setImages(representativeImages); representativeSaggitalImages.add(is); } } // grin1.setImageSeries( representativeSaggitalImages ); return representativeSaggitalImages; } /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#getVerbose() */ @Override public boolean getVerbose() { return (this.verbose); } /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#searchGenes(java.lang.String, java.io.OutputStream) */ @Override public boolean searchGenes(String searchTerm, OutputStream out) throws MalformedURLException, IOException { String args[] = { searchTerm }; String searchGenesUrl = buildUrlString(SEARCH_GENE_URL, args); return (doPageDownload(searchGenesUrl, out)); } /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#setCacheDir(java.lang.String) */ @Override public void setCacheDir(String s) { this.cacheDir = s; } /* * Convieniece method for striping out the images from the image series. Also fully qaulifies URLs for link to allen * brain atlas web site @param imageSeries @return */ /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#setCaching(boolean) */ @Override public void setCaching(boolean v) { this.useFileCache = v; } /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#setErrOut(java.io.PrintStream) */ @Override public void setErrOut(PrintStream out) { this.errOut = out; } /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#setInfoOut(java.io.PrintStream) */ @Override public void setInfoOut(PrintStream out) { this.infoOut = out; } /* * (non-Javadoc) * * @see ubic.gemma.image.aba.AllenBrainAtlasService#setVerbose(boolean) */ @Override public void setVerbose(boolean v) { this.verbose = v; } protected boolean getGene(String gene, OutputStream out) throws MalformedURLException, IOException { String args[] = { gene }; String getGeneUrl = buildUrlString(GET_GENE_URL, args); return (doPageDownload(getGeneUrl, out)); } /** * @param imagePath * @param zoom * @param mimeType * @param out * @return * @throws MalformedURLException * @throws IOException */ protected boolean getImage(String imagePath, Integer zoom, Integer mimeType, OutputStream out) throws MalformedURLException, IOException { String args[] = { mimeType.toString(), zoom.toString(), imagePath }; String getImageUrl = buildUrlString(GET_IMAGE_URL, args); return (doPageDownload(getImageUrl, out)); } protected boolean getImageInfo(Integer imageId, OutputStream out) throws MalformedURLException, IOException { String args[] = { imageId.toString() }; String getImageInfoUrl = buildUrlString(GET_IMAGE_INFO_BYID_URL, args); return (doPageDownload(getImageInfoUrl, out)); } protected boolean getImageInfo(String imagePath, OutputStream out) throws MalformedURLException, IOException { String args[] = { imagePath }; String getImageInfoUrl = buildUrlString(GET_IMAGE_INFO_BYPATH_URL, args); return (doPageDownload(getImageInfoUrl, out)); } protected boolean getImageseries(Integer imageseriesId, OutputStream out) throws MalformedURLException, IOException { String args[] = { imageseriesId.toString() }; String getImageseriesUrl = buildUrlString(GET_IMAGESERIES_URL, args); return (doPageDownload(getImageseriesUrl, out)); } protected boolean getNeuroblast(Integer imageseriesId, String structure, String plane, OutputStream out) throws MalformedURLException, IOException { String getNeuroblastUrl; if (plane == null) { String args[] = { structure, imageseriesId.toString() }; getNeuroblastUrl = buildUrlString(GET_NEUROBLAST_URL, args); } else { String args[] = { structure, imageseriesId.toString(), plane }; getNeuroblastUrl = buildUrlString(GET_NEUROBLAST_PLANE_URL, args); } return (doPageDownload(getNeuroblastUrl, out)); } /** * The allen brain atlas website 1st letter of gene symbol is capatalized, rest are not (webservice is case * sensitive) * * @param geneName * @return */ private String correctCase(String geneName) { return StringUtils.capitalize(StringUtils.lowerCase(geneName)); } private boolean doPageDownload(String urlString, OutputStream out) throws MalformedURLException, IOException { URL url = new URL(urlString); DataInputStream in = null; in = getInput(url); if (in == null) return (false); transferData(in, out); return (true); } private DataInputStream getCachedFile(String cachedName) throws FileNotFoundException { DataInputStream fs = new DataInputStream(new FileInputStream(cachedName)); return (fs); } private File getFile(String fileName) { File outputFile = new File(this.cacheDir + "aba_" + fileName + ".xml"); if (outputFile.exists()) { outputFile.delete(); // wait for file to be deleted before proceeding int i = 5; while ((i > 0) && (outputFile.exists())) { try { Thread.sleep(1000); } catch (InterruptedException ie) { log.error(ie); } i--; } } return outputFile; } private DataInputStream getInput(URL url) throws IOException { if (this.useFileCache) { String cachedName = this.cacheDir + "/" + url.toString().replace("/", "_"); File f = new File(cachedName); if (f.exists()) { if (this.verbose) this.infoOut.println("Using cached file '" + cachedName + "'"); return (getCachedFile(cachedName)); } } HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.connect(); DataInputStream in = new DataInputStream(conn.getInputStream()); if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) { this.errOut.println(conn.getResponseMessage()); return (null); } if (this.verbose) showHeader(conn); if (this.useFileCache) { String cachedName = this.cacheDir + "/" + url.toString().replace("/", "_"); FileOutputStream out = new FileOutputStream(new File(cachedName)); transferData(in, out); return (getCachedFile(cachedName)); } return (in); } private void initDefaults() { this.verbose = false; this.useFileCache = false; this.cacheDir = ConfigUtils.getString("gemma.appdata.home") + ABA_CACHE; File abaCacheDir = new File(this.cacheDir); if (!(abaCacheDir.exists() && abaCacheDir.canRead())) { log.warn("Attempting to create aba cache directory in '" + this.cacheDir + "'"); abaCacheDir.mkdirs(); } this.infoOut = System.out; this.errOut = System.err; } private void showHeader(URLConnection url) { this.infoOut.println(""); this.infoOut.println("URL : " + url.getURL().toString()); this.infoOut.println("Content-Type : " + url.getContentType()); this.infoOut.println("Content-Length : " + url.getContentLength()); if (url.getContentEncoding() != null) this.infoOut.println("Content-Encoding : " + url.getContentEncoding()); } private void transferData(DataInputStream in, OutputStream out) throws IOException { // This is whacked. There must be a better way than throwing an exception. boolean EOF = false; while (!EOF) { try { out.write(in.readUnsignedByte()); } catch (EOFException eof) { EOF = true; } } } }