How to insert a file to google drive path with apache camel java DSL - google-drive-api

I'm running around trying to figure out how to use Apache Camel's google-drive drive-files component to insert some files to a nested folder in the drive. So far below code is able to insert the file to the drive's root folder.
from("timer:bkp?period={{timer.period}}")
.process(new BackupFile())
.to("google-drive://drive-files/insert")
.log("done");
And this is the Processor class
public class BackupFile implements Processor {
private static final String TEST_UPLOAD_FILE = "/path/to/file/imge.jpg";
private static final java.io.File UPLOAD_FILE = new java.io.File(TEST_UPLOAD_FILE);
#Override
public void process(Exchange exchange) throws Exception {
File fileMetadata = new File();
fileMetadata.setTitle(UPLOAD_FILE.getName());
FileContent mediaContent = new FileContent(null, UPLOAD_FILE);
final Map<String, Object> headers = new HashMap<>();
headers.put("CamelGoogleDrive.content", fileMetadata);
headers.put("CamelGoogleDrive.mediaContent", mediaContent);
exchange.getIn().setHeaders(headers);
}
}
FYI I need to define the said nested path before insert i.e do some setup like
setPath("/mydrive/path/tofile");
Any help or leads would be highly appreciated.

After looking around I came across Node.js sample that helped. The missing information all along was that the nested folder needed to exist before we can reference it.What I was expecting was a functionality to create the folder but perhaps this can be added as improvement. The folder's ID (PARENT_ID) can also be found from the url of the folder.
Below code finally worked for me.
ParentReference parRef=new ParentReference();
parRef.setId(PARENT_ID);
List<ParentReference> parents=new ArrayList<>();
parents.add(parRef);
File fileMetadata = new File();
fileMetadata.setTitle(UPLOAD_FILE.getName());
fileMetadata.setParents(parents);
FileContent mediaContent = new FileContent(null, UPLOAD_FILE);
final Map<String, Object> headers = new HashMap<>();
headers.put("CamelGoogleDrive.content", fileMetadata);
headers.put("CamelGoogleDrive.mediaContent", mediaContent);
exchange.getIn().setHeaders(headers);

Related

Include a file in an Android application

I used android studio to create a java app. In the project, I created the "assets" folder, and inside I put the json file that I will need to get the credentials for GmailAPI.
AssetFolder
I wish I could access the json file. I have already tried in many ways but every time it tells me that the file is missing.
This is the code:
public class GmailApi {
public Gmail initService(String userId) throws GeneralSecurityException,
IOException {
JacksonFactory jsonFactory = JacksonFactory.getDefaultInstance();
final GoogleCredentials creds = ServiceAccountCredentials.fromStream(new FileInputStream("gmailapi-android.json"))
.createScoped(GmailScopes.GMAIL_SEND);
final GoogleCredentials delegatedCreds = creds.createDelegated("xxx#xxx.com");
HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(delegatedCreds);
HttpTransport transport = new NetHttpTransport.Builder().build();
// Construct the gmail object.
Gmail service = new Gmail.Builder(transport, jsonFactory, requestInitializer)
.setApplicationName("gmailapi")
.build();
return service;
}
}
Could anyone help me? What should I put in the path to be able to access the json file?
final GoogleCredentials creds = ServiceAccountCredentials.fromStream(new FileInputStream("gmailapi-android.json"))
Did you try to open the file this way?
AssetManager assetManager = getAssets();
InputStream ims = assetManager.open("gmailapi-android.json");

how to fix NullPointerException while loading document to Elasticsearch 7.3

I want to load a JSON string to Elasticsearch version 7.3.
Following is the code i am using for this.
private RestHighLevelClient restHighLevelClient;
String jsonString="//here the complete JSON string";
JSONObject jsonObject = new JSONObject(cojsonStringntent1.toString());
HashMap<String, Object> hashMap = new Gson().fromJson(jsonObject.toString(), HashMap.class);
IndexRequest indexRequest = new IndexRequest("index", "type").source(hashMap);
restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
Exception :
Exception in thread "main" java.lang.NullPointerException
at line restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
If I post the same jsonString via POSTMEN than it is being loaded to ELASTICSEARCH perfectly.
If you are not using spring(as it's not mentioned), you can use below simple code to create a resthighlevelclient.
In below code, I am reading the elasticsearch configuration from a config file, feel free to change it to the way you read the properties or config, or if you just want to quickly test it hardcode the values of host and port
RestHighLevelClient restHighLevelClient = new RestHighLevelClient(
RestClient.builder(new HttpHost(configuration.getElasticsearchConfig().getHost(),
configuration.getElasticsearchConfig().getPort(),
"http")));
Based on your sample code, your restHighLevelClient hasn't been initialized indeed at all. Please find snippet of code below how you could solve this:
#Bean
public RestHighLevelClient elasticRestClient () {
String[] httpHosts = httpHostsProperty.split(";");
HttpHost[] httpHostsAsArray = new HttpHost[httpHosts.length];
int index = 0;
for (String httpHostAsString : httpHosts) {
HttpHost httpHost = new HttpHost(httpHostAsString.split(":")[0], new Integer(httpHostAsString.split(":")[1]), "http");
httpHostsAsArray[index++] = httpHost;
}
RestClientBuilder restClientBuilder = RestClient.builder(httpHostsAsArray)
.setRequestConfigCallback(builder -> builder
.setConnectTimeout(connectTimeOutInMs)
.setSocketTimeout(socketTimeOutInMs)
);
return new RestHighLevelClient(restClientBuilder);
}
and your impl class uses the autowired RestHighLevelClient bean:
#Autowired
private RestHighLevelClient restClient;

Create empty file using Document List API 3.0

I am developing a feature which need to create a new empty file(not document) to Google drive, now I am using document list API 3.0 and I am referring to the document: https://developers.google.com/google-apps/documents-list/#uploading_a_new_document_or_file_with_both_metadata_and_content.
I will upload a zero byte file to the Google drive to generate the empty file.
Now I have a problem during request step 1 and request step 2. After the first Post[resumable-create-media link] request I successfully got the upload location. Then when I request put method to the location, I got a 404 not found error. All of the requests have "GData-Version: 3.0" and "Authorization: accessToken" headers.
I searched a lot from the forum and figured out how to create empty document but could not figure out how to create empty file. Here is my code, could anybody help to see which part is wrong? Thanks in advance.
private final static String PARAM_CONTENT_TYPE = "Content-Type";
private final static String PARAM_UPLOAD_LENGTH = "X-Upload-Content-Length";
private final static String PARAM_UPLOAD_TYPE = "X-Upload-Content-Type";
private final static String CONTENT_TYPE_XML = "application/atom+xml";
private final static String URI_RESUMABLE_RESOURCE = "https://docs.google.com/feeds/upload/create-session/default/private/full";
private final static String ENTITY_NEW_FILE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><entry xmlns=\"http://www.w3.org/2005/Atom\" "
+ "xmlns:docs=\"http://schemas.google.com/docs/2007\"><title>{0}</title></entry>";
#Override
public boolean createNewFile() throws IOException {
String uri = null;
if (ROOT.equals(parentResourceId))
uri = URI_RESUMABLE_RESOURCE;
else
uri = URI_RESUMABLE_RESOURCE + "/%3A" + parentResourceId + "/contents";
try {
StringEntity entity = new StringEntity(MessageFormat.format(ENTITY_NEW_FILE, getName()), Constants.ENCODING);
Map<String, String> headers = new HashMap<String, String>();
headers.put(PARAM_CONTENT_TYPE, CONTENT_TYPE_XML);
headers.put(PARAM_UPLOAD_LENGTH, "0");
headers.put(PARAM_UPLOAD_TYPE, "text/plain");
Map<String, String> params = new HashMap<String, String>();
params.put("convert", "false");
HttpResponse response = helper.execMethodAsResponse(uri, new PostMethod(entity), headers, params);
String location = null;
if ((location = response.getFirstHeader("Location").getValue()) != null) {
headers = new HashMap<String, String>();
headers.put(PARAM_CONTENT_TYPE, "text/plain");
headers.put("Content-Range", "bytes 0-0/0");
//FIXME: Problem occurs here, this put invocation will return 404 not found error.
JsonObject obj = helper.execMethodAsJson(location, new PutMethod(new ByteArrayEntity(new byte[0])), headers, null);
if (obj != null) {
decorateFile(this, obj.get("entry").getAsJsonObject());
return true;
}
}
} catch (UnsupportedEncodingException e) {
}
return false;
}
The easiest way to create an empty file on Google Drive is to use the Google Drive API v2 and send a service.files.insert(File content) request.
You can use the Java sample from the Reference Guide and edit it to not include a MediaContent: https://developers.google.com/drive/v2/reference/files/insert
I have figured out the problem, according to this link: Google Documents List API file upload 400 response
The second put request does not need any additional headers such as "GData-Version: 3.0" and "Authorization: Bearer ****", etc. The only thing need to do is new a put request with the location URI, then it will return response with 201 status code.
Thanks all.

How to serve html file from another directory as ActionResult

I have a specialised case where I wish to serve a straight html file from a Controller Action.
I want to serve it from a different folder other than the Views folder. The file is located in
Solution\Html\index.htm
And I want to serve it from a standard controller action. Could i use return File? And
how do I do this?
Check this out :
public ActionResult Index()
{
return new FilePathResult("~/Html/index.htm", "text/html");
}
If you want to render this index.htm file in the browser then you could create controller action like this:
public void GetHtml()
{
var encoding = new System.Text.UTF8Encoding();
var htm = System.IO.File.ReadAllText(Server.MapPath("/Solution/Html/") + "index.htm", encoding);
byte[] data = encoding.GetBytes(htm);
Response.OutputStream.Write(data, 0, data.Length);
Response.OutputStream.Flush();
}
or just by:
public ActionResult GetHtml()
{
return File(Server.MapPath("/Solution/Html/") + "index.htm", "text/html");
}
So lets say this action is in Home controller and some user hits http://yoursite.com/Home/GetHtml then index.htm will be rendered.
EDIT: 2 other methods
If you want to see raw html of index.htm in the browser:
public ActionResult GetHtml()
{
Response.AddHeader("Content-Disposition", new System.Net.Mime.ContentDisposition { Inline = true, FileName = "index.htm"}.ToString());
return File(Server.MapPath("/Solution/Html/") + "index.htm", "text/plain");
}
If you just want to download file:
public FilePathResult GetHtml()
{
return File(Server.MapPath("/Solution/Html/") + "index.htm", "text/html", "index.htm");
}
I extended wahid's answer to create HtmlResult
Create Html Result which extends FilePathResult
public class HtmlResult : FilePathResult
{
public HtmlResult(string path)
: base(path, "text/html")
{
}
}
Created static method on controller
public static HtmlResult Html(this Controller controller, string path)
{
return new HtmlResult(path);
}
used like we return view
public HtmlResult Index()
{
return this.Html("~/Index.html");
}
Hope it helps
I want put my two cents in. I have found this most terse and it is there already :
public ActionResult Index()
{
var encoding = new System.Text.UTF8Encoding();
var html = ""; //get it from file, from blob or whatever
return this.Content(html, "text/html; charset=utf-8");
}
Can you read the html file in a string and return it in action? It is rendered as Html page as shown below:
public string GetHtmlFile(string file)
{
file = Server.MapPath("~/" + file);
StreamReader streamReader = new StreamReader(file);
string text = streamReader.ReadToEnd();
streamReader.Close();
return text;
}
Home/GetHtmlFile?file=Solution\Html\index.htm
If the destination or storage mechanism of HTML files is complicated then you can you Virtual path provider
Virtual path provider MVC sample
Alternative approach if using .net core is to use a FileProvider.
The files could be in a folder or embedded at compile time.
In this example we will use embedded files.
Add a folder in your project let's say assets, in it create a file myfile.html, add some basic html to the file say
<html>
<head>
<title>Test</title>
</head>
<body>
Hello World
</body>
</html>
Right click on the new file (assuming you are in visual studio) select properties, in the properties screen / build action, select embedded resource. It will add the file to the csproj file.
Right click on your project, edit your csproj file.
Check that your property group contains the following:
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
If not please add it. The csproj should also contain the newly created html file as:
<ItemGroup>
<EmbeddedResource Include="assets\myfile.html" />
</ItemGroup>
To read the file in your controller and pass it to the client requires a file provider which is added to the startup.cs
Edit your startup.cs make sure it includes the HostingEnvironment:
private readonly IHostingEnvironment HostingEnvironment;
public Startup(IHostingEnvironment hostingEnvironment)
{
HostingEnvironment = hostingEnvironment;
}
Then create a file provider and make it a service that can be injected at runtime. Create it as follows:
var physicalProvider = HostingEnvironment.ContentRootFileProvider;
var manifestEmbeddedProvider =
new ManifestEmbeddedFileProvider(Assembly.GetEntryAssembly());
var compositeProvider =
new CompositeFileProvider(physicalProvider, manifestEmbeddedProvider);
services.AddSingleton<IFileProvider>(compositeProvider);
To serve the file go to your controller, use dependency injection to get the FileProvider, create a new service and serve the file. To do this, start with dependency injection by adding the provider to your constructor.
IFileProvider _fileProvider;
public MyController(IFileProvider fileProvider)
{
this._fileProvider = fileProvider;
}
Then use the file provider in your service
[HttpGet("/myfile")]
[Produces("text/html")]
public Stream GetMyFile()
{
// Use GetFileInfo to get details on the file passing in the path added to the csproj
// Using the fileInfo returned create a stream and return it.
IFileInfo fileinfo = _fileProvider.GetFileInfo("assets/myfile.html");
return fileinfo.CreateReadStream();
}
For more info see ASP .Net Core file provider sample and the Microsoft documentation here.

FlyingSaucer: convert an HTML document to PDF ignoring external CSS?

I'm using the following to convert HTML to PDF:
InputStream convert(InputStream fileInputStream) {
PipedInputStream inputStream = new PipedInputStream()
PipedOutputStream outputStream = new PipedOutputStream(inputStream)
new Thread({
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(false);
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(fileInputStream)
ITextRenderer renderer = new ITextRenderer()
renderer.setDocument(document, "")
renderer.layout()
renderer.createPDF(outputStream)
}).start()
return inputStream
}
From the documentation, apparently I should be able to set a "User Agent" resolver somewhere, but I'm not sure where, exactly. Anyone know how to ignore external CSS in a document?
Not the same question but my answer for that one will work here too: Resolving protected resources with Flying Saucer (ITextRenderer)
Override this method:
public CSSResource getCSSResource(String uri) {
return new CSSResource(resolveAndOpenStream(uri));
}
with
public CSSResource getCSSResource(String uri) {
return new CSSResource(new ByteArrayInputStream([] as byte[]));
}