I am searching for a .txt file that is located at change set.
Then I need to create locally over my pc the full path directory of this file.
For example if there a file called"test.txt" that it's located at:
Project1-->Folder1-->Folder2-->test.txt
Till now I have managed to search for this file.
Now I need to fetch the full directory and create similar one over my pc:
Result at my pc:
Folder1-->Folder2-->test.txt
That's what I did to search for the file within a changeset and retrieve it:
public IFileItem getTextFileFile(IChangeSet changeSet, ITeamRepository repository) throws TeamRepositoryException{
IVersionableManager vm = SCMPlatform.getWorkspaceManager(repository).versionableManager();
List changes = changeSet.changes();
IFileItem toReturn = null;
for(int i=0;i<changes.size();i++) {="" <br=""> Change change = (Change) changes.get(i);
IVersionableHandle after = change.afterState();
if( after != null && after instanceof IFileItemHandle) {
IFileItem fileItem = (IFileItem) vm.fetchCompleteState(after, null);
if(fileItem.getName().contains(".txt")) {
toReturn = fileItem;
break;
} else {
continue;
}
}
}
if(toReturn == null){
throw new TeamRepositoryException("Could not find the file");
}
return toReturn;
}
I use RTC:4
Win:XP
Thanks in advance.
I have the following IConfiguration that I fetched by the following:
IWorkspaceManager workspaceManager = SCMPlatform.getWorkspaceManager(repository);
IWorkspaceSearchCriteria wsSearchCriteria = WorkspaceSearchCriteria.FACTORY.newInstance();
wsSearchCriteria.setKind(IWorkspaceSearchCriteria.STREAMS);
wsSearchCriteria.setPartialOwnerNameIgnoreCase(projectAreaName);
List <iworkspacehandle> workspaceHandles = workspaceManager.findWorkspaces(wsSearchCriteria, Integer.MAX_VALUE, Application.getMonitor());
IWorkspaceConnection workspaceConnection = workspaceManager.getWorkspaceConnection(workspaceHandles.get(0),Application.getMonitor());
IComponentHandle component = changeSet.getComponent();
IConfiguration configuration = workspaceConnection.configuration(component);
List lst = new ArrayList<string>();
lst=configuration.locateAncestors(lst,Application.getMonitor());
=========================================
Now to get the full path of the file item ,I made the following method I got from :
https://jazz.net/forum/questions/94927/how-do-i-find-moved-from-location-for-a-movedreparented-item-using-rtc-4-java-api
=========================================
private String getFullPath(List ancestor, ITeamRepository repository)
throws TeamRepositoryException {
String directoryPath = "";
for (Object ancestorObj : ancestor) {
IAncestorReport ancestorImpl = (IAncestorReport) ancestorObj;
for (Object nameItemPairObj : ancestorImpl.getNameItemPairs()) {
NameItemPairImpl nameItemPair = (NameItemPairImpl) nameItemPairObj;
Object item = SCMPlatform.getWorkspaceManager(repository)
.versionableManager()
.fetchCompleteState(nameItemPair.getItem(), null);
String pathName = "";
if (item instanceof IFolder) {
pathName = ((IFolder) item).getName();
}
else if (item instanceof IFileItem) {
pathName = ((IFileItem) item).getName();
}
if (!pathName.equals(""))
directoryPath = directoryPath + "\\" + pathName;
}
}
return directoryPath;
}
=========================================
Related
I'm getting CMISNotFoundException while accessing the root folder even though i already have many documents uploaded to the repository.I'm able to fetch the repository id but getRootFolder throws error
could not fetch folder due to org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException: Object not found
s = d.getSession().session;
p.append("Successfully established session \n");
p.append("id:"+s.getRepositoryInfo().getId()+"\n");
try {
Folder folder = s.getRootFolder();
}catch(Exception e) {
p.append("could not fetch folder due to "+e.toString()+"\n");
}
I'm able to get the root folder now after creating a new repository.But now for applying ACLS i'm facing problem.
LWhen i try to apply ACl to the root folder i get CmisObjectNotFound exception.
When i apply ACL to subfolders, it workds but the permission is not applied correctly.I want to give user1 all the permission and user 2 read permission.But for user1 , now i'm not able to even view the folder.And for user2 i'm able to do everything except download.
I have referred to this link for doing so sap-link
response.getWriter().println("<html><body>");
try {
// Use a unique name with package semantics e.g. com.foo.MyRepository
String uniqueName = "com.vat.VatDocumentsRepo";
// Use a secret key only known to your application (min. 10 chars)
String secretKey = "****";
Session openCmisSession = null;
InitialContext ctx = new InitialContext();
String lookupName = "java:comp/env/" + "EcmService";
EcmService ecmSvc = (EcmService) ctx.lookup(lookupName);
try {
// connect to my repository
openCmisSession = ecmSvc.connect(uniqueName, secretKey);
}
catch (CmisObjectNotFoundException e) {
// repository does not exist, so try to create it
RepositoryOptions options = new RepositoryOptions();
options.setUniqueName(uniqueName);
options.setRepositoryKey(secretKey);
options.setVisibility(Visibility.PROTECTED);
ecmSvc.createRepository(options);
// should be created now, so connect to it
openCmisSession = ecmSvc.connect(uniqueName, secretKey);
openCmisSession.getDefaultContext().setIncludeAcls(true);
openCmisSession.getDefaultContext().setIncludeAllowableActions(true);
openCmisSession.getDefaultContext().setIncludePolicies(false);
}
response.getWriter().println(
"<h3>You are now connected to the Repository with Id "
+ openCmisSession.getRepositoryInfo().getId()
+ "</h3>");
Folder folder = openCmisSession.getRootFolder();
Map<String, String> newFolderProps = new HashMap<String, String>();
newFolderProps.put(PropertyIds.OBJECT_TYPE_ID, "cmis:folder");
newFolderProps.put(PropertyIds.NAME, "Attachments");
try {
folder.createFolder(newFolderProps);
} catch (CmisNameConstraintViolationException e) {
// Folder exists already, nothing to do
}
String userIdOfUser1 = "user1 ";
String userIdOfUser2 = "user2";
response.getWriter().println("<h3>Created By :"+folder.getCreatedBy()+"</h3>");
List<Ace> addAcl = new ArrayList<Ace>();
// build and add ACE for user U1
List<String> permissionsUser1 = new ArrayList<String>();
permissionsUser1.add("cmis:all");
Ace aceUser1 = openCmisSession.getObjectFactory().createAce(userIdOfUser1, permissionsUser1);
addAcl.add(aceUser1);
// build and add ACE for user U2
List<String> permissionsUser2 = new ArrayList<String>();
permissionsUser2.add("cmis:read");
Ace aceUser2 = openCmisSession.getObjectFactory().createAce(userIdOfUser2,
permissionsUser1);
addAcl.add(aceUser2);
response.getWriter().println("<b>Permissions for users"+addAcl.toString()+"</b>");
// list of ACEs which should be removed
List<Ace> removeAcl = new ArrayList<Ace>();
// build and add ACE for user {sap:builtin}everyone
List<String> permissionsEveryone = new ArrayList<String>();
permissionsEveryone.add("cmis:all");
Ace aceEveryone = openCmisSession.getObjectFactory().createAce(
"{sap:builtin}everyone", permissionsEveryone);
removeAcl.add(aceEveryone);
response.getWriter().println("<b>Removing Permissions for users"+removeAcl.toString()+"</b>");
ItemIterable<CmisObject> children = folder.getChildren();
response.getWriter().println("<h1> changing permissions of the following objects: </h1><ul>");
for (CmisObject o : children) {
response.getWriter().println("<li>");
if (o instanceof Folder) {
response.getWriter().println(" createdBy: " + o.getCreatedBy());
o.applyAcl(addAcl, removeAcl, AclPropagation.OBJECTONLY);
response.getWriter().println("Changed permission</li>");
} else {
Document doc = (Document) o;
response.getWriter().println(" createdBy: " + o.getCreatedBy() + " filesize: "
+ doc.getContentStreamLength() + " bytes");
doc.applyAcl(addAcl, removeAcl, AclPropagation.OBJECTONLY);
response.getWriter().println("Changed permission</li>");
}
}
response.getWriter().println("</ul>");
} catch (Exception e) {
response.getWriter().println("<h1>Error: "+e.toString()+"</h1>");
} finally {
response.getWriter().println("</body></html>");
}
I am trying to fill a list myClassTypes with recursive calls to getMyClassTypes(). But it gets initialized every time there is recursive call to the method. And, I am losing few values because of this. I understand that the problem is with declaring locally: List myClassTypes = new ArrayList<>();
But, I don't want to declare the list at the class level.
Here is the code I am working with:
private List<MyClassType> getMyClassTypes(final String path) throws SVNException {
final Collection<SVNDirEntry> svnDirectoryEntries = svnRepository.getDir(path, -1, null, (Collection<SVNDirEntry>) null);
final Iterator<SVNDirEntry> svnDirectoryEntryIterator = svnDirectoryEntries.iterator();
final List<MyClassType> myClassTypes = new ArrayList<>();
while (svnDirectoryEntryIterator.hasNext()) {
final SVNDirEntry entry = svnDirectoryEntryIterator.next();
final String fileName = entry.getName();
if (!path.isEmpty() && path.matches(SUB_DIRECTORY_NAME_PATTERN) && fileName.endsWith(".xml")) {
final MyClassType myClassType = new MyClassType(path, fileName);
myClassTypes.add(myClassType);
}
/*
* Check if the entry is a directory recursively.
*/
if (someCondition) {
getMyClassTypes((path.equals("")) ? entry.getName() : path + "/" + entry.getName());
}
}
return myClassTypes;
}
How to manage the 'myClassTypes' to contain all the values even after 'n times' recursive calls?
Pass a List<MyClassType> instance as argument to the method instead of creating it inside the method.
This way to create just one ArrayList instance, and you can even change the return type to void.
private void getMyClassTypes(final String path, List<MyClassType> myClassTypes) throws SVNException
{
final Collection<SVNDirEntry> svnDirectoryEntries = svnRepository.getDir(path, -1, null, (Collection<SVNDirEntry>) null);
final Iterator<SVNDirEntry> svnDirectoryEntryIterator = svnDirectoryEntries.iterator();
while (svnDirectoryEntryIterator.hasNext()) {
final SVNDirEntry entry = svnDirectoryEntryIterator.next();
final String fileName = entry.getName();
if (!path.isEmpty() && path.matches(SUB_DIRECTORY_NAME_PATTERN) && fileName.endsWith(".xml")) {
final MyClassType myClassType = new MyClassType(path, fileName);
myClassTypes.add(myClassType);
}
/*
* Check if the entry is a directory recursively.
*/
if (someCondition) {
getMyClassTypes((path.equals("")) ? entry.getName() : path + "/" + entry.getName(), myClassTypes);
}
}
}
Add the return value of the recursive call to the current myClassTypes and return it.
if (someCondition) {
myClassTypes.addAll(getMyClassTypes((path.equals("")) ? entry.getName() : path + "/" + entry.getName()));
}
I'm using apache PDFBox from java, and I have a source PDF with multiple optional content groups. What I am wanting to do is export a version of the PDF that includes only the standard content and the optional content groups that were enabled. It is important for my purposes that I preserve any dynamic aspects of the original.... so text fields are still text fields, vector images are still vector images, etc. The reason that this is required is because I intend to ultimately be using a pdf form editor program that does not know how to handle optional content, and would blindly render all of them, so I want to preprocess the source pdf, and use the form editing program on a less cluttered destination pdf.
I've been trying to find something that could give me any hints on how to do this with google, but to no avail. I don't know if I'm just using the wrong search terms, or if this is just something that is outside of what the PDFBox API was designed for. I rather hope it's not the latter. The info shown here does not seem to work (converting the C# code to java), because despite the pdf I'm trying to import having optional content, there does not seem to be any OC resources when I examine the tokens on each page.
for(PDPage page:pages) {
PDResources resources = page.getResources();
PDFStreamParser parser = new PDFStreamParser(page);
parser.parse();
Collection tokens = parser.getTokens();
...
}
I'm truly sorry for not having any more code to show what I've tried so far, but I've just been poring over the java API docs for about 8 hours now trying to figure out what I might need to do this, and just haven't been able to figure it out.
What I DO know how to do is add text, lines, and images to a new PDPage, but I do not know how to retrieve that information from a given source page to copy it over, nor how to tell which optional content group such information is part of (if any). I am also not sure how to copy form fields in the source pdf over to the destination, nor how to copy the font information over.
Honestly, if there's a web page out there that I wasn't able to find with google with the searches that I tried, I'd be entirely happy to read up more about it, but I am really quite stuck here, and I don't know anyone personally that knows about this library.
Please help.
EDIT:
Trying what I understand from what was suggested below, I've written a loop to examine each XObject on the page as follows:
PDResources resources = pdPage.getResources();
Iterable<COSName> names = resources.getXObjectNames();
for(COSName name:names) {
PDXObject xobj = resources.getXObject(name);
PDFStreamParser parser = new PDFStreamParser(xobj.getStream().toByteArray());
parser.parse();
Object [] tokens = parser.getTokens().toArray();
for(int i = 0;i<tokens.length-1;i++) {
Object obj = tokens[i];
if (obj instanceof COSName && obj.equals(COSName.OC)) {
i++;
Object obj = tokens[i];
if (obj instanceof COSName) {
PDPropertyList props = resources.getProperties((COSName)obj);
if (props != null) {
...
However, after an OC key, the next entry in the tokens array is always an Operator tagged as "BMC". Nowhere am I finding any info that I can recognize from the named optional content groups.
Here's a robust solution for removing marked content blocks (open to feedback if anyone finds anything that isn't working right). You should be able to adjust for OC blocks...
This code properly handles nesting and removal of resources (xobject, graphics state and fonts - easy to add others if needed).
public class MarkedContentRemover {
private final MarkedContentMatcher matcher;
/**
*
*/
public MarkedContentRemover(MarkedContentMatcher matcher) {
this.matcher = matcher;
}
public int removeMarkedContent(PDDocument doc, PDPage page) throws IOException {
ResourceSuppressionTracker resourceSuppressionTracker = new ResourceSuppressionTracker();
PDResources pdResources = page.getResources();
PDFStreamParser pdParser = new PDFStreamParser(page);
PDStream newContents = new PDStream(doc);
OutputStream newContentOutput = newContents.createOutputStream(COSName.FLATE_DECODE);
ContentStreamWriter newContentWriter = new ContentStreamWriter(newContentOutput);
List<Object> operands = new ArrayList<>();
Operator operator = null;
Object token;
int suppressDepth = 0;
boolean resumeOutputOnNextOperator = false;
int removedCount = 0;
while (true) {
operands.clear();
token = pdParser.parseNextToken();
while(token != null && !(token instanceof Operator)) {
operands.add(token);
token = pdParser.parseNextToken();
}
operator = (Operator)token;
if (operator == null) break;
if (resumeOutputOnNextOperator) {
resumeOutputOnNextOperator = false;
suppressDepth--;
if (suppressDepth == 0)
removedCount++;
}
if (OperatorName.BEGIN_MARKED_CONTENT_SEQ.equals(operator.getName())
|| OperatorName.BEGIN_MARKED_CONTENT.equals(operator.getName())) {
COSName contentId = (COSName)operands.get(0);
final COSDictionary properties;
if (operands.size() > 1) {
Object propsOperand = operands.get(1);
if (propsOperand instanceof COSDictionary) {
properties = (COSDictionary) propsOperand;
} else if (propsOperand instanceof COSName) {
properties = pdResources.getProperties((COSName)propsOperand).getCOSObject();
} else {
properties = new COSDictionary();
}
} else {
properties = new COSDictionary();
}
if (matcher.matches(contentId, properties)) {
suppressDepth++;
}
}
if (OperatorName.END_MARKED_CONTENT.equals(operator.getName())) {
if (suppressDepth > 0)
resumeOutputOnNextOperator = true;
}
else if (OperatorName.SET_GRAPHICS_STATE_PARAMS.equals(operator.getName())) {
resourceSuppressionTracker.markForOperator(COSName.EXT_G_STATE, operands.get(0), suppressDepth == 0);
}
else if (OperatorName.DRAW_OBJECT.equals(operator.getName())) {
resourceSuppressionTracker.markForOperator(COSName.XOBJECT, operands.get(0), suppressDepth == 0);
}
else if (OperatorName.SET_FONT_AND_SIZE.equals(operator.getName())) {
resourceSuppressionTracker.markForOperator(COSName.FONT, operands.get(0), suppressDepth == 0);
}
if (suppressDepth == 0) {
newContentWriter.writeTokens(operands);
newContentWriter.writeTokens(operator);
}
}
if (resumeOutputOnNextOperator)
removedCount++;
newContentOutput.close();
page.setContents(newContents);
resourceSuppressionTracker.updateResources(pdResources);
return removedCount;
}
private static class ResourceSuppressionTracker{
// if the boolean is TRUE, then the resource should be removed. If the boolean is FALSE, the resource should not be removed
private final Map<COSName, Map<COSName, Boolean>> tracker = new HashMap<>();
public void markForOperator(COSName resourceType, Object resourceNameOperand, boolean preserve) {
if (!(resourceNameOperand instanceof COSName)) return;
if (preserve) {
markForPreservation(resourceType, (COSName)resourceNameOperand);
} else {
markForRemoval(resourceType, (COSName)resourceNameOperand);
}
}
public void markForRemoval(COSName resourceType, COSName refId) {
if (!resourceIsPreserved(resourceType, refId)) {
getResourceTracker(resourceType).put(refId, Boolean.TRUE);
}
}
public void markForPreservation(COSName resourceType, COSName refId) {
getResourceTracker(resourceType).put(refId, Boolean.FALSE);
}
public void updateResources(PDResources pdResources) {
for (Map.Entry<COSName, Map<COSName, Boolean>> resourceEntry : tracker.entrySet()) {
for(Map.Entry<COSName, Boolean> refEntry : resourceEntry.getValue().entrySet()) {
if (refEntry.getValue().equals(Boolean.TRUE)) {
pdResources.getCOSObject().getCOSDictionary(COSName.XOBJECT).removeItem(refEntry.getKey());
}
}
}
}
private boolean resourceIsPreserved(COSName resourceType, COSName refId) {
return getResourceTracker(resourceType).getOrDefault(refId, Boolean.FALSE);
}
private Map<COSName, Boolean> getResourceTracker(COSName resourceType){
if (!tracker.containsKey(resourceType)) {
tracker.put(resourceType, new HashMap<>());
}
return tracker.get(resourceType);
}
}
}
Helper class:
public interface MarkedContentMatcher {
public boolean matches(COSName contentId, COSDictionary props);
}
Optional Content Groups are marked with BDC and EMC. You will have to navigate through all of the tokens returned from the parser and remove the "section" from the array. Here is some C# Code that was posted a while ago - [1]: How to delete an optional content group alongwith its content from pdf using pdfbox?
I investigated that (converting to Java) but couldn't get it work as expected. I managed to remove the content between BDC and EMC and then save the result using the same technique as the sample but the PDF was corrupted. Perhaps that is my lack of C# Knowledge (related to Tuples etc.)
Here is what I came up with, as I said it doesn't work perhaps you or someone else (mkl, Tilman Hausherr) can spot the flaw.
OCGDelete (PDDocument doc, int pageNum, String OCName) {
PDPage pdPage = (PDPage) doc.getDocumentCatalog().getPages().get(pageNum);
PDResources pdResources = pdPage.getResources();
PDFStreamParser pdParser = new PDFStreamParser(pdPage);
int ocgStart
int ocgLength
Collection tokens = pdParser.getTokens();
Object[] newTokens = tokens.toArray()
try {
for (int index = 0; index < newTokens.length; index++) {
obj = newTokens[index]
if (obj instanceof COSName && obj.equals(COSName.OC)) {
// println "Found COSName at "+index /// Found Optional Content
startIndex = index
index++
if (index < newTokens.size()) {
obj = newTokens[index]
if (obj instanceof COSName) {
prop = pdRes.getProperties(obj)
if (prop != null && prop instanceof PDOptionalContentGroup) {
if ((prop.getName()).equals(delLayer)) {
println "Found the Layer to be deleted"
println "prop Name was " + prop.getName()
index++
if (index < newTokens.size()) {
obj = newTokens[index]
if ((obj.getName()).equals("BDC")) {
ocgStart = index
println("OCG Start " + ocgStart)
ocgLength = -1
index++
while (index < newTokens.size()) {
ocgLength++
obj = newTokens[index]
println " Loop through relevant OCG Tokens " + obj
if (obj instanceof Operator && (obj.getName()).equals("EMC")) {
println "the next obj was " + obj
println "after that " + newTokens[index + 1] + "and then " + newTokens[index + 2]
println("OCG End " + ocgLength++)
break
}
index++
}
if (endIndex > 0) {
println "End Index was something " + (startIndex + ocgLength)
}
}
}
}
}
}
}
}
}
}
catch (Exception ex){
println ex.message()
}
for (int i = ocgStart; i < ocgStart+ ocgLength; i++){
newTokens.removeAt(i)
}
PDStream newContents = new PDStream(doc);
OutputStream output = newContents.createOutputStream(COSName.FLATE_DECODE);
ContentStreamWriter writer = new ContentStreamWriter(output);
writer.writeTokens(newTokens);
output.close();
pdPage.setContents(newContents);
}
How do I rename a file using the Google Drive REST API on Android? I have searched the internet however I could, but I can't find how to do this.
I am trying to write a sync method that moves and renames the cloud files if it detects that the local copy has been moved or renamed:
void syncMetadataOnly (com.google.api.services.drive.model.File cloud,
java.io.File local) throws IOException {
Workspace.FINF fileInfo = Workspace.getFileInfo (this, local); // Just my metadata object.
Map<String, String> appProperties = cloud.getAppProperties ();
// We keep track of the last rename and move in our private app properties:
long cloudLastRename = appProperties.containsKey ("last-rename") ?
Long.valueOf (appProperties.get ("last-rename")) : 0;
long cloudLastMove = appProperties.containsKey ("last-move") ?
Long.valueOf (appProperties.get ("last-move")) : 0;
boolean needUpdate = false;
boolean needName = false;
boolean needMove = false;
if (fileInfo.lastRename > cloudLastRename) {
// The file was renamed locally since the last sync.
needName = true;
needUpdate = true;
} else fileInfo.title = cloud.getName ();
String oldRecognizedParent = null;
if (fileInfo.lastMove > cloudLastMove) {
// The file was moved to a different folder locally since the last sync.
oldRecognizedParent = getFirstKnownParentId (cloud); // May be null, if not found.
needMove = true;
needUpdate = true;
}
if (needUpdate) {
cloud.setAppProperties (appProperties);
Drive.Files.Update update = mDriveService.files ().update (fileInfo.driveResourceId, null);
if (needName) update.set /// How do I rename the file?
if (needMove) {
if (oldRecognizedParent != null)
update.setRemoveParents (oldRecognizedParent);
update.setAddParents (fileInfo.driveParentId); // Set to the NEW parent's ID.
}
com.google.api.services.drive.model.File result = update.execute ();
}
}
The closest answer I have found is this, but do I really have to use raw HTTP for this?
I am writing a Java application to download emails using Exchange Web Services. I am using Microsoft's ewsjava API for doing this.
I am able to fetch email headers. But, I am not able to download email attachments using this API. Below is the code snippet.
FolderId folderId = new FolderId(WellKnownFolderName.Inbox, "mailbox#example.com");
findResults = service.findItems(folderId, view);
for(Item item : findResults.getItems()) {
if (item.getHasAttachments()) {
AttachmentCollection attachmentsCol = item.getAttachments();
System.out.println(attachmentsCol.getCount()); // This is printing zero all the time. My message has one attachment.
for (int i = 0; i < attachmentsCol.getCount(); i++) {
FileAttachment attachment = (FileAttachment)attachmentsCol.getPropertyAtIndex(i);
String name = attachment.getFileName();
int size = attachment.getContent().length;
}
}
}
item.getHasAttachments() is returning true, but attachmentsCol.getCount() is 0.
You need to load property Attachments before you can use them in your code. You set it for ItemView object that you pass to FindItems method.
Or you can first find items and then call service.LoadPropertiesForItems and pass findIesults and PropertySet object with added EmailMessageSchema.Attachments
FolderId folderId = new FolderId(WellKnownFolderName.Inbox, "mailbox#example.com");
findResults = service.findItems(folderId, view);
service.loadPropertiesForItems(findResults, new PropertySet(BasePropertySet.FirstClassProperties, EmailMessageSchema.Attachments));
for(Item item : findResults.getItems()) {
if (item.getHasAttachments()) {
AttachmentCollection attachmentsCol = item.getAttachments();
System.out.println(attachmentsCol.getCount());
for (int i = 0; i < attachmentsCol.getCount(); i++) {
FileAttachment attachment = (FileAttachment)attachmentsCol.getPropertyAtIndex(i);
attachment.load(attachment.getName());
}
}
}
Honestly as painful as it is, I'd use the PROXY version instead of the Managed API. It's a pity, but the managed version for java seems riddled with bugs.
before checking for item.getHasAttachments(), you should do item.load(). Otherwise there is a chance your code will not load the attachment and attachmentsCol.getCount() will be 0.
Working code with Exchange Server 2010 :
ItemView view = new ItemView(Integer.MAX_VALUE);
view.getOrderBy().add(ItemSchema.DateTimeReceived, SortDirection.Descending);
FindItemsResults < Item > results = service.findItems(WellKnownFolderName.Inbox, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, true), view);
Iterator<Item> itr = results.iterator();
while(itr.hasNext()) {
Item item = itr.next();
item.load();
ItemId itemId = item.getId();
EmailMessage email = EmailMessage.bind(service, itemId);
if (item.getHasAttachments()) {
System.err.println(item.getAttachments());
AttachmentCollection attachmentsCol = item.getAttachments();
for (int i = 0; i < attachmentsCol.getCount(); i++) {
FileAttachment attachment=(FileAttachment)attachmentsCol.getPropertyAtIndex(i);
attachment.load("C:\\TEMP\\" +attachment.getName());
}
}
}
Little late for the answer, but here is what I have.
HashMap<String, HashMap<String, String>> attachments = new HashMap<String, HashMap<String, String>>();
if (emailMessage.getHasAttachments() || emailMessage.getAttachments().getItems().size() > 0) {
//get all the attachments
AttachmentCollection attachmentsCol = emailMessage.getAttachments();
log.info("File Count: " +attachmentsCol.getCount());
//loop over the attachments
for (int i = 0; i < attachmentsCol.getCount(); i++) {
Attachment attachment = attachmentsCol.getPropertyAtIndex(i);
//log.debug("Starting to process attachment "+ attachment.getName());
//FileAttachment - Represents a file that is attached to an email item
if (attachment instanceof FileAttachment || attachment.getIsInline()) {
attachments.putAll(extractFileAttachments(attachment, properties));
} else if (attachment instanceof ItemAttachment) { //ItemAttachment - Represents an Exchange item that is attached to another Exchange item.
attachments.putAll(extractItemAttachments(service, attachment, properties, appendedBody));
}
}
}
} else {
log.debug("Email message does not have any attachments.");
}
//Extract File Attachments
try {
FileAttachment fileAttachment = (FileAttachment) attachment;
// if we don't call this, the Content property may be null.
fileAttachment.load();
//extract the attachment content, it's not base64 encoded.
attachmentContent = fileAttachment.getContent();
if (attachmentContent != null && attachmentContent.length > 0) {
//check the size
int attachmentSize = attachmentContent.length;
//check if the attachment is valid
ValidateEmail.validateAttachment(fileAttachment, properties,
emailIdentifier, attachmentSize);
fileAttachments.put(UtilConstants.ATTACHMENT_SIZE, String.valueOf(attachmentSize));
//get attachment name
String fileName = fileAttachment.getName();
fileAttachments.put(UtilConstants.ATTACHMENT_NAME, fileName);
String mimeType = fileAttachment.getContentType();
fileAttachments.put(UtilConstants.ATTACHMENT_MIME_TYPE, mimeType);
log.info("File Name: " + fileName + " File Size: " + attachmentSize);
if (attachmentContent != null && attachmentContent.length > 0) {
//convert the content to base64 encoded string and add to the collection.
String base64Encoded = UtilFunctions.encodeToBase64(attachmentContent);
fileAttachments.put(UtilConstants.ATTACHMENT_CONTENT, base64Encoded);
}
//Extract Item Attachment
try {
ItemAttachment itemAttachment = (ItemAttachment) attachment;
PropertySet propertySet = new PropertySet(
BasePropertySet.FirstClassProperties, ItemSchema.Attachments,
ItemSchema.Body, ItemSchema.Id, ItemSchema.DateTimeReceived,
EmailMessageSchema.DateTimeReceived, EmailMessageSchema.Body);
itemAttachment.load();
propertySet.setRequestedBodyType(BodyType.Text);
Item item = itemAttachment.getItem();
eBody = appendItemBody(item, appendedBody.get(UtilConstants.BODY_CONTENT));
appendedBody.put(UtilConstants.BODY_CONTENT, eBody);
/*
* We need to check if Item attachment has further more
* attachments like .msg attachment, which is an outlook email
* as attachment. Yes, we can attach an email chain as
* attachment and that email chain can have multiple
* attachments.
*/
AttachmentCollection childAttachments = item.getAttachments();
//check if not empty collection. move on
if (childAttachments != null && !childAttachments.getItems().isEmpty() && childAttachments.getCount() > 0) {
for (Attachment childAttachment : childAttachments) {
if (childAttachment instanceof FileAttachment) {
itemAttachments.putAll(extractFileAttachments(childAttachment, properties, emailIdentifier));
} else if (childAttachment instanceof ItemAttachment) {
itemAttachments = extractItemAttachments(service, childAttachment, properties, appendedBody, emailIdentifier);
}
}
}
} catch (Exception e) {
throw new Exception("Exception while extracting Item Attachments: " + e.getMessage());
}