Reading parquet files from S3 with custom endpoint in Java - java

I'm trying to find out the best way to read parquet data from S3 storage.
First approach:
BasicSessionCredentials cred = new BasicSessionCredentials(key,secret, "");
AmazonS3 client = AmazonS3ClientBuilder
.standard()
.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration("custom_endpoint", region))
.withCredentials(new AWSStaticCredentialsProvider(cred))
.build();
GetObjectRequest req = new GetObjectRequest("bucket_name", "relative_path", "");
S3Object obj = client.getObject(req);
S3ObjectInputStream cont = obj.getObjectContent();
This way I'm able to read the object, but I couldn't find the way of reading parquet data from InputStream
Second approach:
String SCHEMA_TEMPLATE = "{" +
"\"type\": \"record\",\n" +
" \"name\": \"schema\",\n" +
" \"fields\": [\n" +
" {\"name\": \"timeStamp\", \"type\": \"string\"},\n" +
" {\"name\": \"temperature\", \"type\": \"double\"},\n" +
" {\"name\": \"pressure\", \"type\": \"double\"}\n" +
" ]" +
"}";
String PATH_SCHEMA = "s3a";
Path internalPath = new Path(PATH_SCHEMA, bucketName, folderName);
Schema schema = new Schema.Parser().parse(SCHEMA_TEMPLATE);
Configuration configuration = new Configuration();
configuration.set("fs.s3a.access.key", "key");
configuration.set("fs.s3a.secret.key", "secret");
configuration.set("fs.s3a.endpoint", "custom_endpoint");
AvroReadSupport.setRequestedProjection(configuration, schema);
ParquetReader<GenericRecord> = AvroParquetReader.GenericRecord>builder(internalPath).withConf(configuration).build();
GenericRecord genericRecord = parquetReader.read();
while(genericRecord != null) {
Map<String, String> valuesMap = new HashMap<>();
genericRecord.getSchema().getFields().forEach(field -> valuesMap.put(field.name(), genericRecord.get(field.name()).toString()));
genericRecord = parquetReader.read();
}
But for the second case I'm not able to read data and getting SocketTimeoutException.
Help me to find the right approach
Thanks

Related

setting s3 bucket policy while PutObject

public String getPolicy() throws Exception {
String policy_document = "{\"expiration\": \"2020-01-01T00:00:00Z\",\n" +
" \"conditions\": [ \n" +
" {\"bucket\": \"bucket\"}, \n" +
" [\"starts-with\", \"$Content-Type\", \"image/\"],\n" +
" [\"content-length-range\", 0, 100]\n" +
" ]\n" +
"}";
String aws_secret_key = "xxxxx";
String policy = (new BASE64Encoder()).encode(policy_document.getBytes("UTF-8"))
.replaceAll("\n", "").replaceAll("\r", "");
Mac hmac = Mac.getInstance("HmacSHA1");
hmac.init(new SecretKeySpec(
aws_secret_key.getBytes("UTF-8"), "HmacSHA1"));
String signature = (new BASE64Encoder()).encode(
hmac.doFinal(policy.getBytes("UTF-8")))
.replaceAll("\n", "");
return policy;
}
While uploading -
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setHeader("policy", getPolicy());
s3Client.putObject(bucket, key, inputStream, objectMetadata);
Can we pass policy header like above to reject s3 putObject requests that violate policy conditions ?
I think it is possible via s3Client.setBucketPolicy but is there a way to set these policies for each put request ?

Creating a Directory in azure storage with REST API

I'm trying to create a directory using REST API. Below is the code for Signature. Can you help me to find the issue in the code:
string storageKey = 'storage key';
string storageName = '<storageName>';
Datetime dt = Datetime.now();
string formattedDate = dt.formatGMT('EEE, dd MMM yyyy HH:mm:ss')+ ' GMT';
system.debug('formattedDate--'+formattedDate);
string CanonicalizedHeaders = 'x-ms-date:'+formattedDate+'\nx-ms-version:2016-05-31';
string CanonicalizedResource = '/' + storageName + '/<myShareName>/<DirectoryName>\nrestype:directory';
string StringToSign = 'PUT\n\n\n\n\napplication/xml;charset=utf-8\n\n\n\n\n\n\n' + CanonicalizedHeaders+'\n'+CanonicalizedResource;
system.debug('StringToSign--'+StringToSign);
Blob temp = EncodingUtil.base64Decode(storageKey);
Blob hmac = Crypto.generateMac('HmacSHA256',Blob.valueOf(StringToSign),temp ); //StringToSign
system.debug('oo-'+EncodingUtil.base64Encode(hmac));
HttpRequest req = new HttpRequest();
req.setMethod('PUT');
req.setHeader('content-type', 'application/xml;charset=utf-8');
req.setHeader('content-length', '0');
req.setHeader('x-ms-version','2016-05-31' );
req.setHeader('x-ms-date', formattedDate);
string signature = EncodingUtil.base64Encode(hmac);
string authHeader = 'SharedKey <storageName>'+':'+signature;
req.setHeader('Authorization',authHeader);
req.setEndpoint('https://<storageName>.file.core.windows.net/<myShareName>/<DirectoryName>&restype=directory');
Http http = new Http();
HTTPResponse res= http.send(req);
Refer the link for azure documentation: https://learn.microsoft.com/en-us/rest/api/storageservices/create-directory
I wrote the following java code for your reference, and it works well for me.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import com.microsoft.windowsazure.core.utils.Base64;
public class CreateDirectory {
private static final String account = "jaygong";
private static final String key = "******";
public static void main(String args[]) throws Exception {
System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
String urlString = "http://" + account + ".file.core.windows.net/testshare/testdirectory?restype=directory";
// Proxy proxy = new Proxy(java.net.Proxy.Type.HTTP,new InetSocketAddress("127.0.0.1", 8888));
// URL serverUrl = new URL(urlString);
// HttpURLConnection connection = (HttpURLConnection) serverUrl.openConnection(proxy);
HttpURLConnection connection = (HttpURLConnection) (new URL(urlString)).openConnection();
getFileRequest(connection, account, key);
connection.connect();
System.out.println("Response message : " + connection.getResponseMessage());
System.out.println("Response code : " + connection.getResponseCode());
BufferedReader br = null;
if (connection.getResponseCode() != 200) {
br = new BufferedReader(new InputStreamReader((connection.getErrorStream())));
} else {
br = new BufferedReader(new InputStreamReader((connection.getInputStream())));
}
System.out.println("Response body : " + br.readLine());
}
public static void getFileRequest(HttpURLConnection request, String account, String key) throws Exception {
SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
String date = fmt.format(Calendar.getInstance().getTime()) + " GMT";
String stringToSign = "PUT\n" + "\n" // content encoding
+ "\n" // content language
+ "\n"// content length
+ "\n" // content md5
+ "\n" // content type
+ "\n" // date
+ "\n" // if modified since
+ "\n" // if match
+ "\n" // if none match
+ "\n" // if unmodified since
+ "\n" // range
+ "x-ms-date:" + date + "\nx-ms-version:2015-02-21\n" // headers
+ "/" + account + request.getURL().getPath()+"\nrestype:directory"; // resources
System.out.println("stringToSign : " + stringToSign);
String auth = getAuthenticationString(stringToSign);
System.out.println(auth);
request.setRequestMethod("PUT");
request.setRequestProperty("x-ms-date", date);
request.setRequestProperty("x-ms-version", "2015-02-21");
request.setRequestProperty("Authorization", auth);
request.setRequestProperty("Content-Length", "0");
}
private static String getAuthenticationString(String stringToSign) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(Base64.decode(key), "HmacSHA256"));
String authKey = new String(Base64.encode(mac.doFinal(stringToSign.getBytes("UTF-8"))));
String auth = "SharedKey " + account + ":" + authKey;
return auth;
}
}
Notes:
Please note that System.setProperty("sun.net.http.allowRestrictedHeaders", "true"); in the above code is necessary.
I found a parameter called allowRestrictedHeaders from source code, which was originally designed to limit the use of Http Header for security in the design of API.All of the following are limited:
private static final String[] restrictedHeaders = {
/* Restricted by XMLHttpRequest2 */
//"Accept-Charset",
//"Accept-Encoding",
"Access-Control-Request-Headers",
"Access-Control-Request-Method",
"Connection", /* close is allowed */
"Content-Length",
//"Cookie",
//"Cookie2",
"Content-Transfer-Encoding",
//"Date",
"Expect",
"Host",
"Keep-Alive",
"Origin",
// "Referer",
// "TE",
"Trailer",
"Transfer-Encoding",
"Upgrade",
//"User-Agent",
"Via"
};
allowRestrictedHeaders = ((Boolean)java.security.AccessController.doPrivileged(
new sun.security.action.GetBooleanAction(
"sun.net.http.allowRestrictedHeaders"))).booleanValue();
Hope it helps you.

Constant 401 error with OAuth1 (MCM API)

I've been trying to establish a connection with an API for more than a week now, to no avail. (Magic Card Market's, authentification documentation here and there). I'm supposed to receive a XML file.
I have what MCM call a "widget" access to their API, meaning that I don't have nor need a oauth_token (it's supposed to be an empty string) for the authorization header, and that I'm not supposed to receive nor use an access token/access secret.
The only things I do have are a consumer key (they call it app token sometimes) and a consumer secret.
Here is how I build my Authorization header :
private static String buildOAuthAuthorization(String method, String request)
throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
String mkmAppToken = APICredentials.appToken;
String mkmAppSecret = APICredentials.appSecret;
String realm = "https://www.mkmapi.eu/ws/v1.1/games";
String oauthVersion = "1.0";
String oauthConsumerKey = mkmAppToken;
String oauthToken = "";
String oauthSignatureMethod = "HMAC-SHA1";
String oauthTimestamp = Long.toString(System.currentTimeMillis() / 1000);
String oauthNonce = Long.toString(System.currentTimeMillis());
String paramString = "oauth_consumer_key=" + oauthConsumerKey
+ "oauth_nonce=" + oauthNonce
+ "oauth_signature_method=" + oauthSignatureMethod
+ "oauth_timestamp=" + oauthTimestamp
+ "oauth_token=" + oauthToken
+ "oauth_version=" + oauthVersion;
String baseString = method + "&" + rawUrlEncode(realm) + "&" + rawUrlEncode(paramString);
String signingKey = rawUrlEncode(mkmAppSecret) + "&";
Mac mac = Mac.getInstance("HMAC-SHA1");
SecretKeySpec secret = new SecretKeySpec(signingKey.getBytes(), mac.getAlgorithm());
mac.init(secret);
byte[] digest = mac.doFinal(baseString.getBytes());
byte[] oauthSignature = Base64.encode(digest, Base64.URL_SAFE);
String authorizationProperty = "OAuth "
+ "realm=\"" + realm + "\", "
+ "oauth_version=\"" + oauthVersion + "\", "
+ "oauth_timestamp=\"" + oauthTimestamp + "\", "
+ "oauth_nonce=\"" + oauthNonce + "\", "
+ "oauth_consumer_key=\"" + oauthConsumerKey + "\", "
+ "oauth_token=\""+ oauthToken + "\", "
+ "oauth_signature_method=\"" + oauthSignatureMethod + "\", "
+ "oauth_signature=\"" + oauthSignature + "\"";
System.out.println(authorizationProperty);
return authorizationProperty;
}
The actual request is in an AsyncTask :
public static class oAuthRequest extends AsyncTask<String, Integer, StringReader> {
private int lastCode;
#Override
protected StringReader doInBackground(String... requestURLs) {
String method = requestURLs[0];
String url = requestURLs[1];
StringReader result = null;
try {
String authProperty = buildOAuthAuthorization(method, url);
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.addRequestProperty("Authorization:", authProperty);
lastCode = connection.getResponseCode();
System.out.println("RESPONSE CODE 1 " + lastCode);
// Get content
BufferedReader rd = new BufferedReader(new InputStreamReader(lastCode == 200 ? connection.getInputStream() : connection.getErrorStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = rd.readLine()) != null) {
sb.append(line);
}
rd.close();
result = new StringReader(sb.toString());
} catch (NoSuchAlgorithmException | InvalidKeyException | IOException e) {
e.printStackTrace();
}
return result;
}
}
It seems like no matter what I change, I'm always getting a 401.
Things I've tried :
oauthSignature as a String using Base64.encodeToString()
Nonce generation using SecureRandom
With and without the empty oauthToken
Another timestamp generation method (can't remember what though)
signing key with and without app token (theorically I need only the consumer secret, but you never know)
Using HttpsURLConnection instead of HttpURLConnection (the URI start in https, so I thought, hey. But no)
At least 2-3 other different implementations (one who was basically a copy/paste of the Java example in the documentation of course -- it still kind of is one now)
(Probably a lot of things I can't even remember)
At this point I'm wondering if maybe the issue comes from my keys, as I've tried to use the Postman app to test requests with the same results.

How to access servlet and download attachment?

I have the following code snippet that tries to make an HTTP call to my servlet:
try {
// Construct data
String data = URLEncoder.encode("rpt_type", "UTF-8") + "=" + URLEncoder.encode(reportType, "UTF-8");
data += "&" + URLEncoder.encode("rpt_project", "UTF-8") + "=" + URLEncoder.encode(reportProject, "UTF-8");
data += "&" + URLEncoder.encode("rpt_mrv_creator", "UTF-8") + "=" + URLEncoder.encode(reportMrvCreator, "UTF-8");
data += "&" + URLEncoder.encode("rpt_gi_recipient", "UTF-8") + "=" + URLEncoder.encode(reportGiRecipient, "UTF-8");
data += "&" + URLEncoder.encode("rpt_plant", "UTF-8") + "=" + URLEncoder.encode(reportPlant, "UTF-8");
data += "&" + URLEncoder.encode("rpt_sloc", "UTF-8") + "=" + URLEncoder.encode(reportStorageLoc, "UTF-8");
data += "&" + URLEncoder.encode("rpt_gi_no", "UTF-8") + "=" + URLEncoder.encode(reportGiNo, "UTF-8");
data += "&" + URLEncoder.encode("date_sap_gi_fr", "UTF-8") + "=" + URLEncoder.encode(reportDateGiFrom, "UTF-8");
data += "&" + URLEncoder.encode("date_sap_gi_to", "UTF-8") + "=" + URLEncoder.encode(reportDateGiTo, "UTF-8");
data += "&" + URLEncoder.encode("rpt_partno", "UTF-8") + "=" + URLEncoder.encode(reportPartNo, "UTF-8");
data += "&" + URLEncoder.encode("rpt_so_no", "UTF-8") + "=" + URLEncoder.encode(reportSvcOrderNo, "UTF-8");
data += "&" + URLEncoder.encode("date_scan_fr", "UTF-8") + "=" + URLEncoder.encode(reportDateScanFrom, "UTF-8");
data += "&" + URLEncoder.encode("date_scan_to", "UTF-8") + "=" + URLEncoder.encode(reportDateScanTo, "UTF-8");
System.out.println("[data]\n" + data);
// Send data
String urlString = "http://localhost:8080/aerobook/GIStatusReportDownload?" + data;
System.out.println("[url] " + urlString);
URL url = new URL(urlString);
URLConnection conn = url.openConnection();
//conn.setDoOutput(true);
//OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
//wr.write(data);
//wr.flush();
// Get the response
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = rd.readLine()) != null) {
System.out.println(line);
}
//wr.close();
rd.close();
} catch (Exception e) {
}
My debug output:
[data]
rpt_type=d&rpt_project=aaa&rpt_mrv_creator=bbb&rpt_gi_recipient=ccc&rpt_plant=ddd&rpt_sloc=eee&rpt_gi_no=fff&date_sap_gi_fr=02%2F05%2F2012&date_sap_gi_to=03%2F05%2F2012&rpt_partno=ggg&rpt_so_no=hhh&date_scan_fr=26%2F05%2F2012&date_scan_to=31%2F05%2F2012
[url] http://localhost:8080/aerobook/GIStatusReportDownload?rpt_type=d&rpt_project=aaa&rpt_mrv_creator=bbb&rpt_gi_recipient=ccc&rpt_plant=ddd&rpt_sloc=eee&rpt_gi_no=fff&date_sap_gi_fr=02%2F05%2F2012&date_sap_gi_to=03%2F05%2F2012&rpt_partno=ggg&rpt_so_no=hhh&date_scan_fr=26%2F05%2F2012&date_scan_to=31%2F05%2F2012
On my servlet (in a separate file from the code above), I generate an Excel file for download:
res.setContentType(sContentType);
res.setHeader("Content-Disposition", "attachment;filename=\"" + sExcelFileName + "\"");
OutputStream oOutStrm = res.getOutputStream();
wbBook.write(oOutStrm);
oOutStrm.close();
My issue here is that from the URL generated by my code (as shown in the debug output above), I can access my servlet and I manage to get the Save-As dialog.
I'd like to get the contents of the file generated for use within my code. Is there any way I can get the attachment from my code, in byte stream or any other format?
Edit #3: Cleaned up the top
When you enter the URI into the browser, you are doing a GET request. Your client Java code however produces a POST request, and sends the parameters in the body, not the URI.
You may want to look at an HTTP trace and compare.
I want to get the contents of the excel file on my code, but so far it's not working.
I find no errors in the code.
I believe you want to convert content from input stream to an HSSFWorkbook object.
Following code snippet will help you on it.
java.net.URLConnection conn = url.openConnection();
java.io.InputStream is = conn.getInputStream();
org.apache.poi.hssf.usermodel.HSSFWorkbook workBook = new org.apache.poi.hssf.usermodel.HSSFWorkbook( is );
System.out.println( "Number of Sheets: " + workBook.getNumberOfSheets() );
org.apache.poi.hssf.usermodel.HSSFSheet sheet = workBook.getSheetAt( 0 );
System.out.println( "Sheet Name: " + sheet.getSheetName() );
// rest of your code to handle the captured workBook
// cheers
Check wbBook.write(oOutStrm); whether anything has been written into outputStream, also you need call oOutStrm.flash() before close it.
I doubt that the problem lies at OutputStream oOutStrm = res.getOutputStream();.
I bet res is HttpServletResponse and it returns a ServletOutputStream suitable for writing binary data in the response. The servlet container does not encode the binary data
Check API
So, You might not be getting anything except fileName.
In Servlet Try
FileOutputStream stream = new FileOutputStream("c:/excel/Book1.xls");
workBook.write(stream);

Twitter API Failed to validate oauth signature and token java

I'm trying to access resources of a twitter account with http protocol, in an Android app. Twitter uses the open authentication standard OAuth for authentication, consequently I'm following the example in https://dev.twitter.com/docs/auth/oauth#Overview.
My problem is :
I whant to acquiring a request token but when I make the request to the endpoint https://api.twitter.com/oauth/request_token the response is "Failed to validate oauth signature and token".
My code :
FOR SIGNATURE STEP
Timestamp and Nonce
oauthTimestamp = String.valueOf(new Date().getTime());
oauthNonce = Base64.encodeToString(oauthTimestamp.getBytes(),Base64.DEFAULT);
//remove /n at the end of the string
oauthNonce = oauthNonce.substring(0, oauthNonce.length() - 1);
Signature base string
String signatureBaseString =
"POST"
+ "&"
+ URLEncoder.encode("https://api.twitter.com/oauth/request_token")
+ "&"
+ URLEncoder.encode("oauth_callback=" + redirectUrl)
+ URLEncoder.encode("&" + "oauth_consumer_key=" + consumerKey)
+ URLEncoder.encode("&" + "oauth_nonce=" + oauthNonce)
+ URLEncoder.encode("&" + "oauth_signature_method=" + "HMAC-SHA1")
+ URLEncoder.encode("&" + "oauth_timestamp=" + oauthTimestamp)
+ URLEncoder.encode("&" + "oauth_version=" + "1.0");
signature call
signature = getSignatureToken(applicationSecret, signatureBaseString, "HmacSHA1");
signature method
private String getSignatureToken(String consumerSecret, String baseString, String algotithm) {
byte[] keyBytes = (consumerSecret+"&").getBytes();
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, algotithm);
Mac mac;
String res = null;
try {
mac = Mac.getInstance(algotithm);
mac.init(secretKeySpec);
byte[] rawHmac = mac.doFinal((baseString).getBytes());
res = android.util.Base64.encodeToString(rawHmac, android.util.Base64.DEFAULT);
res = res.substring(0, res.length() - 1);
System.out.println("MAC : " + res);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
return res;
}
REQUEST TOKEN STEP
HttpResponse response;
HttpPost authorization = new HttpPost("https://api.twitter.com/oauth/request_token");
final String headerValue =
"OAuth " +
"oauth_nonce=\""+oauthNonce+"\", " +
"oauth_callback=\""+redirectUrl+"\", " +
"oauth_signature_method=\"HMAC-SHA1\", " +
"oauth_timestamp=\""+oauthTimestamp+"\", " +
"oauth_consumer_key=\""+consumerKey+"\", " +
"oauth_signature=\""+URLEncoder.encode(signature)+"\", " +
"oauth_version=\"1.0\"";
authorization.addHeader("Authorization", headerValue);
response = this.httpClient.execute(authorization);
System.out.println(EntityUtils.toString(response.getEntity()));
response = this.httpClient.execute(authorization) give me HTTP/1.1 401 Unauthorized
Any ideas?
Thanks
Well, you'll have to debug this in stages, but one thing I find strange: why are you removing the last character of the HMAC (signature) in getSignatureToken()? That could break the Base64 encoding.

Categories