Fixing a few bugs in the statistics printout.
[jpf-core.git] / src / peers / gov / nasa / jpf / vm / JPF_gov_nasa_jpf_CachedROHttpConnection.java
1 /*
2  * Copyright (C) 2014, United States Government, as represented by the
3  * Administrator of the National Aeronautics and Space Administration.
4  * All rights reserved.
5  *
6  * The Java Pathfinder core (jpf-core) platform is licensed under the
7  * Apache License, Version 2.0 (the "License"); you may not use this file except
8  * in compliance with the License. You may obtain a copy of the License at
9  * 
10  *        http://www.apache.org/licenses/LICENSE-2.0. 
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and 
16  * limitations under the License.
17  */
18
19 package gov.nasa.jpf.vm;
20
21 import gov.nasa.jpf.Config;
22 import gov.nasa.jpf.JPF;
23 import gov.nasa.jpf.JPFConfigException;
24 import gov.nasa.jpf.annotation.MJI;
25 import gov.nasa.jpf.util.FileUtils;
26 import gov.nasa.jpf.util.JPFLogger;
27 import gov.nasa.jpf.vm.MJIEnv;
28 import gov.nasa.jpf.vm.NativePeer;
29
30 import java.io.ByteArrayOutputStream;
31 import java.io.File;
32 import java.io.IOException;
33 import java.io.InputStream;
34 import java.net.MalformedURLException;
35 import java.net.URL;
36 import java.util.HashMap;
37
38 /**
39  * very simple URLConnection model that can be used for reading static URL contents
40  *
41  * The data can be stored in/read from the file system, and is cached
42  * to avoid DOS by means of model checking
43  */
44 public class JPF_gov_nasa_jpf_CachedROHttpConnection extends NativePeer {
45
46   static JPFLogger logger = JPF.getLogger("http");
47
48   File cacheDir;
49   HashMap<String,byte[]> dataCache;
50   
51   public JPF_gov_nasa_jpf_CachedROHttpConnection (Config conf){
52     String cacheDirPath = conf.getString("http.cache_dir");
53     if (cacheDirPath != null){
54       cacheDir = new File(cacheDirPath);
55
56       if (!cacheDir.exists()){
57         cacheDir.mkdir();
58       }
59       if (!cacheDir.isDirectory()){
60         throw new JPFConfigException("illegal http.cache_dir entry: " + cacheDirPath);
61       }
62     }
63
64     dataCache = new HashMap<String,byte[]>();
65   }
66
67   private static String getCacheFileName( String url){
68     String fn = url.replace('/', '^');
69     fn = fn.replace(':', '%');
70
71     return fn;
72   }
73
74   private byte[] getDataFromCachedFile (String url){
75     byte[] data = null;
76     String cacheFileName = getCacheFileName(url);
77     File cacheFile = new File(cacheDir, cacheFileName);
78     if (cacheFile.isFile()) {
79       try {
80         data = FileUtils.getContents(cacheFile);
81       } catch (IOException iox) {
82         logger.warning("can't read http data from cached file ", cacheFile.getPath());
83       }
84
85       if (data != null) {
86         logger.info("reading contents of ", url, " from file ", cacheFile.getPath());
87         dataCache.put(url, data);
88       }
89     }
90
91     return data;
92   }
93
94   private byte[] getDataFromURL (String surl){
95     byte[] data = null;
96
97     try {
98       URL url = new URL(surl);
99       InputStream is = url.openStream();
100
101       if (is != null) {
102         ByteArrayOutputStream os = new ByteArrayOutputStream(is.available());
103         byte[] buf = new byte[1024];
104
105         for (int n = is.read(buf); n >= 0; n = is.read(buf)) {
106           os.write(buf, 0, n);
107         }
108         is.close();
109
110         data = os.toByteArray();
111         dataCache.put(surl, data);
112
113         logger.info("reading contents of ", surl, " from server");
114
115         if (cacheDir != null) {
116           String cacheFileName = getCacheFileName(surl);
117           File cacheFile = new File(cacheDir, cacheFileName);
118           try {
119             FileUtils.setContents(cacheFile, data);
120             logger.info("storing contents of ", surl, " to file ", cacheFile.getPath());
121           } catch (IOException iox) {
122             logger.warning("can't store to cache directory ", cacheFile.getPath());
123           }
124         }
125
126         return data;
127       }
128     } catch (MalformedURLException mux){
129       logger.warning("mallformed URL ", surl);
130     } catch (IOException ex) {
131       logger.warning("reading URL data ", surl, " failed with ", ex.getMessage());
132     }
133
134     return data;
135   }
136
137   @MJI
138   public int getContents__Ljava_lang_String_2___3B (MJIEnv env, int objRef, int surlRef){
139     String url = env.getStringObject(surlRef);
140
141     // first we check if it's already cached in memory
142     byte[] data = dataCache.get(url);
143
144     if (data != null){
145       logger.info("using cached contents of ", url);
146
147     } else {
148       // see if we can get it from the cacheDir
149       if (cacheDir != null){
150         data = getDataFromCachedFile(url);
151       }
152
153       // if that didn't produce anything, we have to reach out to the net
154       if (data == null){
155         data = getDataFromURL( url);
156       }
157     }
158
159     if (data != null){
160       return env.newByteArray(data);
161     } else {
162       return MJIEnv.NULL;
163     }
164   }
165 }