Error when using box-java-sdk - box-api

I have tried to create App user with box-java-sdk example in that link
https://github.com/box/box-java-sdk
And here is the code parameters :
private static final String CLIENT_ID = "qve5jn#############yz6azyh7tabfs";
private static final String CLIENT_SECRET = "kELXWLp8e#############KjKOayc";
private static final String ENTERPRISE_ID = "946313";
private static final String PUBLIC_KEY_ID = "l925y3o8";
private static final String PRIVATE_KEY_FILE = "/home/baddar/.ssh/private_key.pem";
private static final String PRIVATE_KEY_PASSWORD = "hello";
private static final String APP_USER_NAME = "mbaddar1";
private static final int MAX_CACHE_ENTRIES = 100;
However , I always have the error
{"error":"invalid_grant","error_description":"Please check the 'exp'
claim."}
Any ideas ?

I'll explain why you are seeing this error, and then how to fix it.
When the Box Java SDK generates a request for the App User access token, it uses the current UTC time as part of this request. If the Unix time on your local machine and the Box server are out of sync, you will see the exp claim error.
To fix this error, update the Unix time on your machine to match the Unix time from this site. Then retry your request to generate the App User access token.

Related

Converting CSV file to JSON and send it to ActiveMQ queue

My aim is to read a CSV file, convert it to JSON and send the generated JSON one by one to ActiveMQ queue. My Code below:
final BindyCsvDataFormat bindy=new BindyCsvDataFormat(camelproject.EquityFeeds.class);
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
CamelContext _ctx = new DefaultCamelContext();
_ctx.addComponent("jms", JmsComponent.jmsComponentAutoAcknowledge(connectionFactory));
_ctx.addRoutes(new RouteBuilder() {
public void configure() throws Exception {
from("file:src/main/resources?fileName=data-sample.csv")
.unmarshal(bindy)
.marshal()
.json(JsonLibrary.Jackson).log("${body}")
.to("file:src/main/resources/?fileName=emp.json");
}
});
EquityFeeds is my POJO class in the above code.
Issues:
No Output is produced. "emp.json" file does not get generated at the given location.
Also how do I split the generated JSON into individual JSON's and send it to ActiveMQ queue like what I did for XML as below:
.split(body().tokenizeXML("equityFeeds", null)).streaming().to("jms:queue:xml.upstream.queue");
EquityFeeds (POJO):
#CsvRecord(separator = ",",skipFirstLine = true)
public class EquityFeeds {
#DataField(pos = 1)
private String externalTransactionId;
#DataField(pos = 2)
private String clientId;
#DataField(pos = 3)
private String securityId;
#DataField(pos = 4)
private String transactionType;
#DataField(pos = 5)
private Date transactionDate;
#DataField(pos = 6)
private float marketValue;
#DataField(pos = 7)
private String priorityFlag;
// getters and setters...
}
Please kindly help. Please tell me where I am going wrong. Need help desperately. Stuck in this issue and not able to move forward. Any help would be highly appreciated. I have really tried hard, searched Google and tried various options but nothing is working.
Please Note: I commented the .marshal() and .json() to check if the .unmarshal() is working but the unmarshal is also not working as "emp.json" is not getting created.
If nothing happens at all when starting the route then it is most likely due to the relative path you passed to the file component. Probably the execution directory of your Java process is not where you think it is and the file is not found. To simplify things I suggest you start with an absolute path. Once everything else is working figure out the correct relative path (your base should be the value of the user.dir system property).
Re your question about splitting the contents: This is answered in the documentation.
This works for me (Camel 3.1):
public class CsvRouteBuilder extends EndpointRouteBuilder {
#Override
public void configure() {
DataFormat bindy = new BindyCsvDataFormat(BindyModel.class);
from(file("/tmp?fileName=simpsons.csv"))
.unmarshal(bindy)
.split(body())
.log("Unmarshalled model: ${body}")
.marshal().json()
.log("Marshalled to JSON: ${body}")
// Unique file name for the JSON output
.setHeader(Exchange.FILE_NAME, () -> UUID.randomUUID().toString() + ".json")
.to(file("/tmp"));
}
}
// Use lombok to generate all the boilerplate stuff
#ToString
#Getter
#Setter
#NoArgsConstructor
// Bindy record definition
#CsvRecord(separator = ";", skipFirstLine = true, crlf = "UNIX")
public static class BindyModel {
#DataField(pos = 1)
private String firstName;
#DataField(pos = 2)
private String middleName;
#DataField(pos = 3)
private String lastName;
}
Given this input in /tmp/simpsons.csv
firstname;middlename;lastname
Homer;Jay;Simpson
Marge;Jacqueline;Simpson
the log output looks like this
Unmarshalled model: RestRouteBuilder.BindyModel(firstName=Homer, middleName=Jay, lastName=Simpson)
Marshalled to JSON: {"firstName":"Homer","middleName":"Jay","lastName":"Simpson"}
Unmarshalled model: RestRouteBuilder.BindyModel(firstName=Marge, middleName=Jacqueline, lastName=Simpson)
Marshalled to JSON: {"firstName":"Marge","middleName":"Jacqueline","lastName":"Simpson"}
and two json files are written in /tmp.

Is AwsCrypto thread safe? Can we create the object of AWSCrypto once and use it for all the requests?

Can we create the object of AwsCrypto just once and reuse it for all the request? Basically I want to create the KMSClient with AwsCrypto which can be used for encryption and decryption for multiple CMKs.
Below is the sample code:
public class KMSClient {
final private AwsCrypto awsCrypto;
final private Map<String, KmsMasterKeyProvider> kmsMasterKeyProviderMap;
public KMSClient(AwsCrypto awsCrypto){
this.awsCrypto = awsCrypto;
this.kmsMasterKeyProviderMap = new HashMap<>();
}
public byte[] encrypt(final byte[] data, final String customerManagedKeyId) {
return awsCrypto.encryptData(getKmsMasterKeyProvider(customerManagedKeyId), data).getResult();
}
public byte[] decrypt(final byte[] data, final String customerManagedKeyId) {
return awsCrypto.decryptData(getKmsMasterKeyProvider(customerManagedKeyId), data).getResult();
}
private KmsMasterKeyProvider getKmsMasterKeyProvider(final String customerManagedKeyId){
return kmsMasterKeyProviderMap.computeIfAbsent(customerManagedKeyId,
k -> KmsMasterKeyProvider.builder().withKeysForEncryption(k).build());
}
AwsCrypto is thread safe except for setEncryptionAlgorithm and setEncryptionFrameSize. Those two methods are safe to call from multiple threads as long as every thread using that object is on board with changing the state. If one thread makes a change without others being ready for it, there will be trouble.

How to get Logback in a custom layout when parameterized logging?

I have created a custom layout.
Here is my code:
private static final Logger log = LoggerFactory.getLogger(AccountLoginHelper.class);
...
log.info("Successful Login: {}", userName);
I can see in the debugger that userName is filled with "myid" before the call.
But the output in the message looks like this:
Successful Login: {}
I need it to look like this:
Successful Login: myid
This is the code in my customLayout:
#Override
public synchronized String doLayout(ILoggingEvent event) {
String message = event.getMessage();
Just figured it out. Need to change
String message = event.getMessage()
to
String message = event.getFormattedMessage()

Can the initial step of Box API use be automated?

I am the admin of an enterprise account at Box, and I'm working on an automated integration to update our users' email addresses and set their quotas, based on our enterprise' internal catalog.
Although the Box API documentation seems targeted at other usage scenarios, I can gather that once I get an access_token/refresh_token pair, that refresh_token is valid for 60 days, and I can get a new one at any time during that period.
Being of the conviction that "something always goes wrong", I'm just wondering if there is any way of automating the initial step of getting an access_token/refresh_token pair, that doesn't require a browser and manual interaction. I'm afraid that IF the refresh_token is lost or becomes invalid due to an update at Box or similar, no one here will remember how you went about getting that initial token pair by hand.
If there isn't a way to do it automatically, I'll just live with it, but I don't want to give up without having asked explicitly to know that I didn't just miss something. :-)
[Is there] any way of automating the initial step of getting an access_token/refresh_token pair, that doesn't require a browser and manual interaction
No, there are no authZ/authN shortcuts. That goes double for accounts that can manage an entire enterprise, given their power and reach.
I'm afraid ... no one here will remember how you went about getting that initial token pair by hand.
One way to resolve this might be to implement something like this:
Create a Box app with the 'manage an enterprise' scope.
Create a web app in your domain that simply implements the OAuth2 workflow.
Store the resulting access/refresh token pair in your persistence layer of choice
If/when something goes wrong due to authZ/authN issues, have your script notify a group email account that someone needs to go to the web app and request a new token.
There are sample web apps available to help get you started. (Python, Asp.NET MVC)
... The Box API documentation seems targeted at other usage scenarios...
A lot of the enterprise-specific stuff is found in the Users and Events parts of the API, and the As-User feature makes the entire API enterprise-ready. It's pretty neat.
You can build a workarround with an webclient like this:
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.ExecutionException;
import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.ElementNotFoundException;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlButton;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlPasswordInput;
import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput;
import com.gargoylesoftware.htmlunit.html.HtmlTextInput;
public class BoxAuth {
private String key;
private String email;
private String password;
private String redirectUrl;
private final String AUTH_URL;
public BoxAuth(String key, String email, String password, String redirectUrl) {
super();
this.key = key;
this.email = email;
this.password = password;
this.redirectUrl = redirectUrl;
this.AUTH_URL = "https://www.box.com/api/oauth2/authorize?response_type=code&client_id=" + key + "&redirect_uri=" + this.redirectUrl;
}
public String authorize() throws IOException, InterruptedException, ExecutionException {
System.out.println("AUTHORIZING: " + AUTH_URL);
final WebClient webClient = new WebClient(BrowserVersion.FIREFOX_17);
HtmlPage loginPage = webClient.getPage(AUTH_URL);
final HtmlPage grantAccessePage = this.authorizeLogin(loginPage);
return this.authorizeGrantAccess(grantAccessePage);
}
private HtmlPage authorizeLogin(HtmlPage page) throws IOException {
final HtmlForm loginForm = page.getFormByName("login_form");
loginForm.getInputByName("password");
final HtmlTextInput emailField = (HtmlTextInput) loginForm.getInputByName("login");
emailField.setValueAttribute(this.email);
final HtmlPasswordInput passwordField = (HtmlPasswordInput) loginForm.getInputByName("password");
passwordField.setValueAttribute(this.password);
final HtmlSubmitInput loginButton = loginForm.getInputByName("login_submit");
final HtmlPage result = loginButton.click();
try {
final HtmlForm test = result.getFormByName("login_form");
throw new Exception("BoxAPI: Wrong login data!!!");
} catch (ElementNotFoundException e) {
}
return result;
}
private String authorizeGrantAccess(HtmlPage grantAccessePage) throws IOException, InterruptedException, ExecutionException {
final HtmlForm grantAccessForm = grantAccessePage.getHtmlElementById("consent_form");
final HtmlButton grantAccess = grantAccessForm.getButtonByName("consent_accept");
final HtmlPage codePage = grantAccess.click();
URL url = codePage.getUrl();
String result = "";
if (url.toString().contains("&code=")) {
result = url.toString().substring(url.toString().indexOf("&code="));
result = result.replace("&code=", "");
}
return result;
}
}
as redirect_url u can use something like "https://app.box.com/services/yourservice"

Adding Hibernate objects to MySQL concurrently

I am Hibernate newbie, and developing a servlet which gets its parameters from a URL, creates a Hibernate object, then stores it into a MySQL database.
I am sending 1000 URLs concurrently. When I look at the MySQL table, it adds only the last object to the database.
doGet method:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//HttpSession session = request.getSession(true);
//session.putValue("uid", count);
String id = request.getParameter("id");
String url = request.getParameter("url");
String lastVisitTime = request.getParameter("lastVisitTime");
String visitCount = request.getParameter("visitCount");
String title = request.getParameter("title");
String typedCount = request.getParameter("typedCount");
HistoryItem hi = new HistoryItem(id, url, lastVisitTime, visitCount, title, typedCount);
File f = new File("C:\\Users\\atılay\\Desktop\\apache-tomcat-7.0.30-windows-x64\\jspservlets\\UserModeling\\src\\hibernate.cfg.xml");
SessionFactory sessionFactory = new Configuration().configure(f).buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(hi);
session.getTransaction().commit();
session.flush();
session.close();
}
HistoryItem:
public class HistoryItem {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
#Basic(optional = false)
private int i;
private String id = "";
private String url = "";
private String lastVisitTime = "";
private String visitCount = "";
private String title = "";
private String typedCount = "";
}
What is the problem? I could not find any solution.
If you're creating an object/entity to be saved into the database, you shouldn't be setting it's ID.
Allocating the ID happens when the object is saved -- and this is Hibernate's responsibility. Having the ID already set, means HB considers the object has been saved already.
Really this is not a very good question, or coding style, or example.
'Sending 1000 URL concurrently'. What does that mean? You have 1000 browsers open at once, and send a request from all of them simultaneously? Talk sense.
Your SessionFactory should be kept in the webapp or servlet. This code is doing an entire Hibernate startup & initialization, for every page request.
File f = new File("C:\\Users\\atılay\\Desktop\\apache-tomcat-7.0.30-windows-x64\\jspservlets\\UserModeling\\src\\hibernate.cfg.xml");
SessionFactory sessionFactory = new Configuration().configure(f).buildSessionFactory();
Get rid of 'ID' as a parameter -- or else use it optionally, to load & edit records -- and do the Hibernate setup properly.
Then your project might work.