aboutsummaryrefslogtreecommitdiff
path: root/src/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessRunDescription.java
blob: a6b64027b468e31bcf81833caf994a7713f6a91f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/**
 * 
 */
package com.galois.fiveui;



import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Type;
import java.util.List;

import org.apache.log4j.Logger;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonIOException;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSyntaxException;

/**
 * @author bjones
 *
 */
public class HeadlessRunDescription {

	private static Logger logger = Logger.getLogger("com.galois.fiveui.HeadlessRunDescription");
	private static String _crawlType;
	private List<HeadlessAtom> _atoms;
    private static String _firefoxProfile;
	
	public HeadlessRunDescription (List<HeadlessAtom> atoms) {
		_atoms = atoms;
	}
	
	public List<HeadlessAtom> getAtoms() {
		return _atoms;
	}
	
	public int size() {
		return _atoms.size();
	}
	
    /**
     * Parse a JSON file into a HeadlessRunDescription
     * 
     * @param runDescFileName The file to load.
     * @return A populated HeadlessRunDescription object.
     * @throws FileNotFoundException if runDescFile can't be found.
     */
    public static HeadlessRunDescription parse(String runDescFileName) 
            throws FileNotFoundException {
        HeadlessRunDescription runDescr = null;
        try {
            GsonBuilder gsonBuilder = new GsonBuilder();
            gsonBuilder.registerTypeAdapter(HeadlessRunDescription.class, 
                    new HeadlessRunDescription.Deserializer(runDescFileName));
            Gson gson = gsonBuilder.create();
            Reader in = new InputStreamReader(new FileInputStream(runDescFileName));
            runDescr = gson.fromJson(in, HeadlessRunDescription.class);
        } catch (JsonSyntaxException e) {
            System.err.println("We were unable to parse the run description at: "+runDescFileName);
            System.err.println(e.getLocalizedMessage());

            e.printStackTrace();
            throw new IllegalStateException("Could not parse run description");
        } catch (JsonIOException e) {
            System.err.println("We were unable to load the run description at: "+runDescFileName);
            System.err.println(e.getLocalizedMessage());
            
            e.printStackTrace();
            throw new IllegalStateException("Could not parse run description");
        }
        return runDescr;
    }

    public static class Deserializer implements JsonDeserializer<HeadlessRunDescription> {
    	
    	private String _fn; // stores the filename on disk being parsed
    	private String _ctxDir; // stores the parent dir of _fn
    	
        public Deserializer(String fn) {
        	_fn = fn;
        	_ctxDir = new File(_fn).getParent();
            if (null == _ctxDir) {
                 _ctxDir = ".";
             }
        }
        
        public static void reportError(JsonElement json) {
        	logger.error("HeadlessRunDescription.parse: ran into unexpected jsonElement type: \""+json+"\"");
        	logger.error("                              " + json.getAsString());
        }
        
        /**
         * Gracefully lookup property 'prop' in JsonObject 'obj'.
         * 
         * @param obj a JSON object
         * @param prop a key string to lookup in the JSON object
         * @return string property or null if the prop doesn't resolve
         */
        public static String objGetString(JsonObject obj, String prop) {
        	JsonElement value = obj.get(prop);
        	if (null == value) {
        		logger.warn("HeadlessRunDescription.parse: failed to lookup JSON property: " + prop);
        	}
        	return null == value ? null : value.getAsString();
        }
        
        public HeadlessRunDescription deserialize(JsonElement json, Type typeOfT,
                JsonDeserializationContext context) throws JsonParseException {
        	
        	String ruleSetDir;
        	JsonArray arr;
        	
        	if (json.isJsonObject()) { // check if the description is an extended one
        		JsonObject obj = json.getAsJsonObject();
        		ruleSetDir = objGetString(obj, "rulePath");
        		String runDescDir = new File(_fn).getParent();
        		if (null != runDescDir) {
        			ruleSetDir = runDescDir + File.separator + ruleSetDir;
        		}
        		
        	    String ffProfile = objGetString(obj, "firefoxProfile");
        		if (null != ffProfile) {
        			ffProfile = runDescDir + File.separator + ffProfile;
        		}
        		_firefoxProfile = ffProfile;
        	    
        		_crawlType = objGetString(obj, "crawlType");
        		arr = obj.get("runs").getAsJsonArray();
        	} else if (json.isJsonArray()) { // description has only a list of URL/rule pairs
        		ruleSetDir = _ctxDir;
        		_crawlType = "none";
        		_firefoxProfile = null; // indicates that webdriver setup code should make a blank temp profile
        		arr = json.getAsJsonArray();
        	} else {
        		reportError(json);
        		return new HeadlessRunDescription(null);
        	}
            
            Builder<HeadlessAtom> atoms = ImmutableList.builder();
            for (JsonElement jsonElement : arr) {
                // we only care about json objects, so if anything else is found,
                // skip this loop:
                if (!jsonElement.isJsonObject()) {
                    continue;
                }
                try {
                    
                	JsonObject obj = jsonElement.getAsJsonObject();
                	atoms.add(HeadlessAtom.fromJsonObject(obj, ruleSetDir));
                } catch (IOException e) {
                	logger.error("HeadlessAtom.parse: error parsing ruleSet file: " + e.getMessage());
                	System.exit(1);
                } catch (IllegalStateException e) {
                    e.printStackTrace();
                	reportError(jsonElement);
                }
            }
            
            return new HeadlessRunDescription(atoms.build());
        }
    }
    
    public String getCrawlType() {
    	return _crawlType;
    }
    
    public String toString() {
        Gson gson = new Gson();
        return gson.toJson(this);
    }
    
    public String getFirefoxProfile() {
        return _firefoxProfile;
    }
    
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        for (HeadlessAtom a: _atoms) {
	        result = prime * result + a.hashCode();
        }
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        HeadlessRunDescription other = (HeadlessRunDescription) obj;
        if (_atoms == null) {
            if (other._atoms != null)
                return false;
        } else if (!_atoms.equals(other._atoms))
            return false;
        
        return true;
    }

}