|
VolD 0.1
|
00001 package de.zib.vold.client; 00002 00003 import de.zib.vold.common.VoldInterface; 00004 import de.zib.vold.common.Key; 00005 import de.zib.vold.common.URIKey; 00006 00007 import java.util.Collection; 00008 import java.util.List; 00009 import java.util.ArrayList; 00010 import java.util.Set; 00011 import java.util.HashSet; 00012 import java.util.Map; 00013 import java.util.HashMap; 00014 00015 import org.springframework.util.MultiValueMap; 00016 import org.springframework.util.LinkedMultiValueMap; 00017 00018 import org.slf4j.Logger; 00019 import org.slf4j.LoggerFactory; 00020 00021 import org.springframework.context.ApplicationContext; 00022 import org.springframework.context.support.ClassPathXmlApplicationContext; 00023 00024 import org.springframework.web.client.RestTemplate; 00025 import org.springframework.http.ResponseEntity; 00026 import org.springframework.http.HttpStatus; 00027 00033 public class RESTClient implements VoldInterface 00034 { 00035 protected final Logger log = LoggerFactory.getLogger( this.getClass() ); 00036 00037 private String baseURL; 00038 00039 private ApplicationContext context; 00040 private RestTemplate rest; 00041 00042 private String enc = "utf-8"; 00043 00047 public RESTClient( ) 00048 { 00049 baseURL = null; 00050 00051 context = new ClassPathXmlApplicationContext( "classpath:META-INF/client-context.xml" ); 00052 rest = ( RestTemplate )context.getBean( "restTemplate", RestTemplate.class ); 00053 00054 if( null == rest ) 00055 { 00056 throw new IllegalStateException( "Could not get bean rest out of client-context.xml!" ); 00057 } 00058 } 00059 00065 public RESTClient( String baseURL ) 00066 { 00067 context = new ClassPathXmlApplicationContext( "classpath:META-INF/client-context.xml" ); 00068 rest = ( RestTemplate )context.getBean( "restTemplate", RestTemplate.class ); 00069 00070 if( null == rest ) 00071 { 00072 throw new IllegalStateException( "Could not get bean rest out of client-context.xml!" ); 00073 } 00074 00075 this.baseURL = baseURL; 00076 } 00077 00083 public void setBaseURL( String baseURL ) 00084 { 00085 this.baseURL = baseURL; 00086 } 00087 00091 public void setEnc( String enc ) 00092 { 00093 this.enc = enc; 00094 } 00095 00099 public void checkState( ) 00100 { 00101 if( null == this.baseURL ) 00102 { 00103 throw new IllegalStateException( "Tried to operate on VoldClient while it had not been initialized yet. Set the baseURL before!" ); 00104 } 00105 } 00106 00110 @Override 00111 public Map< String, String > insert( String source, Map< Key, Set< String > > map ) 00112 { 00113 // guard 00114 { 00115 log.trace( "Insert: " + map.toString() ); 00116 00117 checkState(); 00118 00119 if( null == map ) 00120 { 00121 throw new IllegalArgumentException( "null is no valid argument!" ); 00122 } 00123 } 00124 00125 // build greatest common scope 00126 String commonscope; 00127 { 00128 List< String > scopes = new ArrayList< String >( map.size() ); 00129 00130 for( Key k: map.keySet() ) 00131 { 00132 scopes.add( k.get_scope() ); 00133 } 00134 00135 commonscope = getGreatestCommonPrefix( scopes ); 00136 } 00137 00138 // build variable map 00139 String uri; 00140 { 00141 uri = buildURI( null ); 00142 log.debug( "URI: " + uri ); 00143 } 00144 00145 // build request body 00146 MultiValueMap< String, String > request = new LinkedMultiValueMap< String, String >(); 00147 { 00148 for( Map.Entry< Key, Set< String > > entry: map.entrySet() ) 00149 { 00150 // remove common prefix from scope 00151 String scope = entry.getKey().get_scope().substring( commonscope.length() ); 00152 String type = entry.getKey().get_type(); 00153 String keyname = entry.getKey().get_keyname(); 00154 00155 URIKey key = new URIKey( source, scope, type, keyname, false, false, enc ); 00156 String urikey = key.toURIString(); 00157 00158 for( String value: entry.getValue() ) 00159 { 00160 request.add( urikey, value ); 00161 } 00162 } 00163 } 00164 00165 // get response from Server 00166 ResponseEntity< Map< String, String > > response; 00167 { 00168 Object obj = rest.postForEntity( baseURL + commonscope, request, HashMap.class ); 00169 00170 if( obj instanceof ResponseEntity< ? > ) 00171 { 00172 response = ( ResponseEntity< Map< String, String > > )obj; 00173 } 00174 else 00175 { 00176 throw new RuntimeException( "THIS SHOULD NEVER HAPPEN!" ); 00177 } 00178 } 00179 00180 return response.getBody(); 00181 } 00182 00189 @Override 00190 public Map< String, String > refresh( String source, Set< Key > set ) 00191 { 00192 // guard 00193 { 00194 log.trace( "Refresh: " + set.toString() ); 00195 00196 checkState(); 00197 00198 if( null == set ) 00199 { 00200 throw new IllegalArgumentException( "null is no valid argument!" ); 00201 } 00202 } 00203 00204 // build greatest common scope 00205 String commonscope; 00206 { 00207 List< String > scopes = new ArrayList< String >( set.size() ); 00208 00209 for( Key k: set ) 00210 { 00211 scopes.add( k.get_scope() ); 00212 } 00213 00214 commonscope = getGreatestCommonPrefix( scopes ); 00215 } 00216 00217 // build variable map 00218 String uri; 00219 { 00220 uri = buildURI( null ); 00221 log.debug( "URI: " + uri ); 00222 } 00223 00224 // build request body 00225 MultiValueMap< String, String > request = new LinkedMultiValueMap< String, String >(); 00226 { 00227 for( Key entry: set ) 00228 { 00229 // remove common prefix from scope 00230 String scope = entry.get_scope().substring( commonscope.length() ); 00231 String type = entry.get_type(); 00232 String keyname = entry.get_keyname(); 00233 00234 URIKey key = new URIKey( source, scope, type, keyname, true, false, enc ); 00235 String urikey = key.toURIString(); 00236 00237 request.add( urikey, "" ); 00238 } 00239 } 00240 00241 // get response from Server 00242 ResponseEntity< Map< String, String > > response; 00243 { 00244 Object obj = rest.postForEntity( baseURL + commonscope, request, HashMap.class ); 00245 00246 if( obj instanceof ResponseEntity< ? > ) 00247 { 00248 response = ( ResponseEntity< Map< String, String > > )obj; 00249 } 00250 else 00251 { 00252 throw new RuntimeException( "THIS SHOULD NEVER HAPPEN!" ); 00253 } 00254 } 00255 00256 return response.getBody(); 00257 } 00258 00265 @Override 00266 public Map< String, String > delete( String source, Set< Key > set ) 00267 { 00268 // guard 00269 { 00270 log.trace( "Delete: " + set.toString() ); 00271 00272 checkState(); 00273 00274 if( null == set ) 00275 { 00276 throw new IllegalArgumentException( "null is no valid argument!" ); 00277 } 00278 } 00279 00280 // build greatest common scope 00281 String commonscope; 00282 { 00283 List< String > scopes = new ArrayList< String >( set.size() ); 00284 00285 for( Key k: set ) 00286 { 00287 scopes.add( k.get_scope() ); 00288 } 00289 00290 commonscope = getGreatestCommonPrefix( scopes ); 00291 } 00292 00293 // build variable map 00294 String uri; 00295 { 00296 uri = buildURI( null ); 00297 log.debug( "URI: " + uri ); 00298 } 00299 00300 // build request body 00301 MultiValueMap< String, String > request = new LinkedMultiValueMap< String, String >(); 00302 { 00303 for( Key entry: set ) 00304 { 00305 // remove common prefix from scope 00306 String scope = entry.get_scope().substring( commonscope.length() ); 00307 String type = entry.get_type(); 00308 String keyname = entry.get_keyname(); 00309 00310 URIKey key = new URIKey( source, scope, type, keyname, false, true, enc ); 00311 String urikey = key.toURIString(); 00312 00313 request.add( urikey, "" ); 00314 } 00315 } 00316 00317 // get response from Server 00318 ResponseEntity< Map< String, String > > response; 00319 { 00320 Object obj = rest.postForEntity( baseURL + commonscope, request, HashMap.class ); 00321 00322 if( obj instanceof ResponseEntity< ? > ) 00323 { 00324 response = ( ResponseEntity< Map< String, String > > )obj; 00325 } 00326 else 00327 { 00328 throw new RuntimeException( "THIS SHOULD NEVER HAPPEN!" ); 00329 } 00330 } 00331 00332 return response.getBody(); 00333 } 00334 00341 @Override 00342 public Map< Key, Set< String > > lookup( Set< Key > keys ) 00343 { 00344 // TODO: lookup has to adjust scope appropriate and eventually merge different requests 00345 00346 // guard 00347 { 00348 log.trace( "Lookup: " + keys.toString() ); 00349 00350 checkState(); 00351 00352 if( null == keys ) 00353 { 00354 throw new IllegalArgumentException( "null is no valid argument!" ); 00355 } 00356 } 00357 00358 // build variable map 00359 String uri; 00360 { 00361 uri = buildURI( keys ); 00362 log.debug( "URI: " + uri ); 00363 } 00364 00365 // get responseEntity from Server 00366 ResponseEntity< Map< Key, Set< String > > > response; 00367 { 00368 Object obj = rest.getForEntity( uri, Map.class, new HashMap< String, String >() ); 00369 00370 if( obj instanceof ResponseEntity< ? > ) 00371 { 00372 response = ( ResponseEntity< Map< Key, Set< String > > > )obj; 00373 } 00374 else 00375 { 00376 throw new RuntimeException( "THIS SHOULD NEVER HAPPEN!" ); 00377 } 00378 00379 if( response.getStatusCode() != HttpStatus.OK ) 00380 { 00381 if( response.hasBody() ) 00382 { 00383 throw new RuntimeException( "Something went wrong on server (" + baseURL + ")... Got body: " + response.getBody() ); 00384 } 00385 else 00386 { 00387 throw new RuntimeException( "Something went wrong on remote server (" + baseURL + ")..." ); 00388 } 00389 } 00390 } 00391 00392 // process and return results 00393 { 00394 if( response.hasBody() ) 00395 { 00396 return response.getBody(); 00397 } 00398 else 00399 { 00400 return null; 00401 } 00402 } 00403 } 00404 00412 public Map< String, String > insert( String source, Key key, Set< String > values ) 00413 { 00414 Map< Key, Set< String > > map = new HashMap< Key, Set< String > >(); 00415 map.put( key, values ); 00416 return insert( source, map ); 00417 } 00418 00425 public Map< Key, Set< String > > lookup( Key key ) 00426 { 00427 Set< Key > keys = new HashSet< Key >(); 00428 keys.add( key ); 00429 return lookup( keys ); 00430 } 00431 00438 private String getGreatestCommonPrefix( Collection< String > words ) 00439 { 00440 if( null == words ) 00441 { 00442 throw new IllegalArgumentException( "Cannot build the greatest common prefix out of an empty set of words!" ); 00443 } 00444 00445 String commonprefix = words.iterator().next(); 00446 00447 for( String w: words ) 00448 { 00449 commonprefix = getCommonPrefix( commonprefix, w ); 00450 } 00451 00452 return commonprefix; 00453 } 00454 00462 private String getCommonPrefix( String a, String b ) 00463 { 00464 for( int i = 1; i < b.length(); ++i ) 00465 { 00466 if( a.length() < i ) 00467 { 00468 return a; 00469 } 00470 00471 if( ! a.substring( i-1, i ).equals( b.substring( i-1, i ) ) ) 00472 { 00473 return a.substring( 0, i-1 ); 00474 } 00475 } 00476 00477 return b; 00478 } 00479 00486 private String buildURI( Collection< Key > keys ) 00487 { 00488 if( null == keys ) 00489 { 00490 return baseURL; 00491 } 00492 00493 StringBuilder sb = new StringBuilder( baseURL + "?" ); 00494 00495 for( Key k: keys ) 00496 { 00497 00498 // TODO: urlencode keyname and type... 00499 sb.append( k.get_keyname() ); 00500 sb.append( ":" ); 00501 sb.append( k.get_type() ); 00502 sb.append( "&" ); 00503 } 00504 00505 return sb.toString(); 00506 } 00507 }