001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package com.thebuzzmedia.exiftool;
031
032import java.io.BufferedReader;
033import java.io.File;
034import java.io.IOException;
035import java.io.InputStreamReader;
036import java.io.StringReader;
037import java.io.StringWriter;
038import java.util.ArrayList;
039import java.util.List;
040
041import com.hp.hpl.jena.query.Query;
042import com.hp.hpl.jena.query.QueryExecution;
043import com.hp.hpl.jena.query.QueryExecutionFactory;
044import com.hp.hpl.jena.query.QueryFactory;
045import com.hp.hpl.jena.query.QuerySolution;
046import com.hp.hpl.jena.query.ResultSet;
047import com.hp.hpl.jena.rdf.model.Model;
048import com.hp.hpl.jena.rdf.model.ModelFactory;
049import com.hp.hpl.jena.rdf.model.Resource;
050import com.hp.hpl.jena.util.ResourceUtils;
051
052public class RDFExifTool extends ExifTool {
053        
054        private String nameSpace;
055
056        public RDFExifTool(String rdfNameSpace){
057                super();
058                this.nameSpace = rdfNameSpace;
059        }
060        
061        public String getImageRDF(File image, Tag... tags)
062                        throws IllegalArgumentException, SecurityException, IOException {
063                return getImageRDF(image, Format.NUMERIC, tags);
064        }
065        
066        public String getImageRDF(File image, String realName, Tag... tags) throws IllegalArgumentException, SecurityException, IOException {
067                return getImageRDF(image, Format.NUMERIC, realName,tags);
068        }
069        
070        public String getImageRDF(File image, Format format,  Tag... tags) throws IllegalArgumentException, SecurityException, IOException{
071                return getImageRDF(image, Format.NUMERIC, image.getName(),tags);
072        }
073        public String getImageRDF(File image, Format format, String realName, Tag... tags)
074                        throws IllegalArgumentException, SecurityException, IOException {
075                if (image == null)
076                        throw new IllegalArgumentException(
077                                        "image cannot be null and must be a valid stream of image data.");
078                if (format == null)
079                        throw new IllegalArgumentException("format cannot be null");
080                if (tags == null || tags.length == 0)
081                        throw new IllegalArgumentException(
082                                        "tags cannot be null and must contain 1 or more Tag to query the image for.");
083                if (!image.canRead())
084                        throw new SecurityException(
085                                        "Unable to read the given image ["
086                                                        + image.getAbsolutePath()
087                                                        + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it.");
088
089                long startTime = System.currentTimeMillis();
090
091                if (DEBUG)
092                        log("Querying %d tags from image: %s", tags.length,
093                                        image.getAbsolutePath());
094
095                long exifToolCallElapsedTime = 0;
096
097                List<String> args = new ArrayList<String>();
098
099                // Clear process args
100                args.clear();
101                log("\tUsing ExifTool in non-daemon mode (-stay_open False)...");
102
103                /*
104                 * Since we are not using a stayOpen process, we need to setup the
105                 * execution arguments completely each time.
106                 */
107                args.add(EXIF_TOOL_PATH);
108
109                args.add("-X");
110
111                for (int i = 0; i < tags.length; i++)
112                        args.add("-" + tags[i].getName());
113
114                args.add(image.getAbsolutePath());
115
116                // Run the ExifTool with our args.
117                BufferedReader reader = startRDFExifToolProcess(args);
118
119                // Begin tracking the duration ExifTool takes to respond.
120                exifToolCallElapsedTime = System.currentTimeMillis();
121
122                String line;
123                StringBuilder builder = new StringBuilder();
124                while ((line = reader.readLine()) != null) {
125                        builder.append(line);
126                        builder.append('\n');
127                }
128
129                // Print out how long the call to external ExifTool process took.
130                log("\tFinished reading ExifTool response in %d ms.",
131                                (System.currentTimeMillis() - exifToolCallElapsedTime));
132                reader.close();
133
134                if (DEBUG)
135                        log("\tImage Meta Processed in %d ms [queried %d tags]",
136                                        (System.currentTimeMillis() - startTime), tags.length);
137
138                String rdfString = builder.toString();
139                Model model = ModelFactory.createDefaultModel();
140                model.read(new StringReader(rdfString), String.format("%s#",nameSpace));
141                
142                String queryString = "SELECT ?o {?o ?p ?v}";
143                Query query = QueryFactory.create(queryString) ;
144                QueryExecution qexec = QueryExecutionFactory.create(query,model);
145                
146                try {
147                        ResultSet results = qexec.execSelect();
148                        for(;results.hasNext();){
149                                QuerySolution soln = results.nextSolution();
150                                Resource r = soln.getResource("o");
151                                log("Renaming resource");
152                                ResourceUtils.renameResource(r, String.format("%s#%s",nameSpace,realName));
153                        }
154                } 
155                catch (Exception e) {}
156                finally {qexec.close();}
157                StringWriter writer = new StringWriter();
158                model.write(writer);
159                return writer.toString();
160        }
161
162        private BufferedReader startRDFExifToolProcess(List<String> args) {
163                Process proc = null;
164
165                log("\tAttempting to start external ExifTool process using args: %s",
166                                args);
167
168                try {
169                        proc = new ProcessBuilder(args).start();
170                        log("\t\tSuccessful");
171                } catch (Exception e) {
172                        String message = "Unable to start external ExifTool process using the execution arguments: "
173                                        + args
174                                        + ". Ensure ExifTool is installed correctly and runs using the command path '"
175                                        + EXIF_TOOL_PATH
176                                        + "' as specified by the 'exiftool.path' system property.";
177
178                        log(message);
179                        throw new RuntimeException(message, e);
180                }
181
182                log("\tSetting up Read/Write streams to the external ExifTool process...");
183                log("\t\tSuccessful, returning streams to caller.");
184                return new BufferedReader(new InputStreamReader(proc.getInputStream()));
185        }
186
187}