Unable to create folder in repositry through CMIS - cmis

I am new to this and trying to create folder in repositry, but it is showing some exception.Help me out wtih this thanks in advance.
Here Is my code
SessionFactory sessionFactory = SessionFactoryImpl.newInstance();
Map<String, String> parameter = new HashMap<String, String>();
// ECM user credentials
parameter.put(SessionParameter.USER, "User");
parameter.put(SessionParameter.PASSWORD, "password");
parameter.put(SessionParameter.ATOMPUB_URL, "URL");
parameter.put(SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
// Get a list of repositories retrieved by the atompub CMIS endpoint (for Alfresco there is only one element)
List<Repository> repositories = sessionFactory.getRepositories(parameter);
// Create CMIS session to the repository
Session session = repositories.get(0).createSession();
System.out.println("Root Folder Name: "+session.getRepositoryInfo().getRootFolderId());
Folder subFolder = null;
Folder parentFolder = session.getRootFolder();
try {
subFolder = (Folder) session.getObjectByPath(parentFolder.getPath() + "/" + "folderName");
System.out.println("Folder already existed!");
} catch (CmisObjectNotFoundException onfe) {
Map props = new HashMap();
props.put("cmis:objectTypeId", "cmis:folder");
props.put("cmis:name", "folderName");
subFolder = parentFolder.createFolder(props);
String subFolderId = subFolder.getId();
System.out.println("Created new folder: " + subFolderId);
}
Getting This error-----
Exception in thread "main" org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException: Conflict
at org.apache.chemistry.opencmis.client.bindings.spi.atompub.AbstractAtomPubService.convertStatusCode(AbstractAtomPubService.java:482)
at org.apache.chemistry.opencmis.client.bindings.spi.atompub.AbstractAtomPubService.post(AbstractAtomPubService.java:629)
at org.apache.chemistry.opencmis.client.bindings.spi.atompub.ObjectServiceImpl.createFolder(ObjectServiceImpl.java:158)
at org.apache.chemistry.opencmis.client.runtime.SessionImpl.createFolder(SessionImpl.java:814)
at org.apache.chemistry.opencmis.client.runtime.FolderImpl.createFolder(FolderImpl.java:136)
at org.apache.chemistry.opencmis.client.runtime.FolderImpl.createFolder(FolderImpl.java:479)
at com.reva.test.main(test.java:55)

The path of the root folder is / and you are adding /folderName to it. So, the final path you are sending to the server is //folderName and that's an invalid path.
Use the method getObjectByPath(String parentPath, String name) for save path concatenation.

Related

How to set a custom store URL for NSPersistentContainer

How can I set a custom store.sqlite URL to NSPersistentContainer?
I have found an ugly way, subclassing NSPersistentContainer:
final public class PersistentContainer: NSPersistentContainer {
private static var customUrl: URL?
public init(name: String, managedObjectModel model: NSManagedObjectModel, customStoreDirectory baseUrl:URL?) {
super.init(name: name, managedObjectModel: model)
PersistentContainer.customUrl = baseUrl
}
override public class func defaultDirectoryURL() -> URL {
return (customUrl != nil) ? customUrl! : super.defaultDirectoryURL()
}
}
Is there a nice way?
Background: I need to save to an App Groups shared directory.
You do this with the NSPersistentStoreDescription class. It has an initializer which you can use to provide a file URL where the persistent store file should go.
let description = NSPersistentStoreDescription(url: myURL)
Then, use NSPersistentContainer's persistentStoreDescriptions attribute to tell it to use this custom location.
container.persistentStoreDescriptions = [description]
Note: myURL must provide the complete /path/to/model.sqlite, even if it does not exist yet. It will not work to set the parent directory only.
Expanding on Tom's answer, when you use NSPersistentStoreDescription for any purpose, be sure to init with NSPersistentStoreDescription(url:) because in my experience if you use the basic initializer NSPersistentStoreDescription() and loadPersistentStores() based on that description, it will overwrite the existing persistent store and all its data the next time you build and run. Here's the code I use for setting the URL and description:
let container = NSPersistentContainer(name: "MyApp")
let storeDirectory = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
// or
let storeDirectory = NSPersistentContainer.defaultDirectoryURL()
let url = storeDirectory.appendingPathComponent("MyApp.sqlite")
let description = NSPersistentStoreDescription(url: url)
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
container.persistentStoreDescriptions = [description]
container.loadPersistentStores { (storeDescription, error) in
if let error = error as? NSError {
print("Unresolved error: \(error), \(error.userInfo)")
}
}
I just find out that the location of db created by PersistentContainer is different from db created by UIManagedDocument. Here is a snapshot of db location by UIManagedDocument:
and the following codes are used to create the db:
let fileURL = db.fileURL // url to ".../Documents/defaultDatabase"
let fileExist = FileManager.default.fileExists(atPath: fileURL.path)
if fileExist {
let state = db.documentState
if state.contains(UIDocumentState.closed) {
db.open()
}
} else {
// Create database
db.save(to: fileURL, for:.forCreating)
}
It looks like that the db referred by PersistentContainer is actually the file further down under folder "StoreContent" as "persistentStore"
This may explain why the db "defaultDatabase" in my case cannot be created by PersistentContainer if you want to specify your customized db file, or causing crash since folder already existed. I further verified this by appending a file name "MyDb.sqlite" like this:
let url = db.fileURL.appendingPathComponent("MyDb.sqlite")
let storeDesription = NSPersistentStoreDescription(url: url)
container.persistentStoreDescriptions = [storeDesription]
print("store description \(container.persistentStoreDescriptions)"
// store description [<NSPersistentStoreDescription: 0x60000005cc50> (type: SQLite, url: file:///Users/.../Documents/defaultDatabase/MyDb.sqlite)
container.loadPersistentStores() { ... }
Here is the new MyDb.sqlite:
Based on the above analysis, if you have codes like this:
if #available(iOS 10.0, *) {
// load db by using PersistentContainer
...
} else {
// Fallback on UIManagedDocument method to load db
...
}
Users' device may be on iOS pre 10.0 and later be updated to 10+. For this change, I think that the url has to be adjusted to avoid either crash or creating a new(empty) db (losing data).
This is the code that I use to initialize a pre-populated sqlite db that works consistently. Assuming you will use this db as read only then there is no need to copy it to the Documents dir on the device.
let repoName = "MyPrepopulatedDB"
let container = NSPersistentContainer(name: repoName)
let urlStr = Bundle.main.path(forResource: "MyPrepopulatedDB", ofType: "sqlite")
let url = URL(fileURLWithPath: urlStr!)
let persistentStoreDescription = NSPersistentStoreDescription(url: url)
persistentStoreDescription.setOption(NSString("true"), forKey: NSReadOnlyPersistentStoreOption)
container.persistentStoreDescriptions = [persistentStoreDescription]
container.loadPersistentStores(completionHandler: { description, error in
if let error = error {
os_log("ERROR: Failed to initialize persistent store, error is \(error.localizedDescription)")
} else {
os_log("Successfully loaded persistent store, \(description)")
}
})
Some very important steps/items to keep in mind:
when constructing the URL to the sqlite file use the URL(fileURLWithPath:) form of the initializer. It seems that core data requires file based URLs, otherwise you will get an error.
I used a unit test to run some code in order to create/pre-populate the db in the simulator.
I located the full path to the sqlite file by adding a print statement inside the completion block of loadPersistentStores(). The description parameter of this block contains the full path to the sqlite file.
Then using Finder you can copy/paste that file in the app project.
At the same location as the sqlite file there are two other files (.sqlite-shm & .sqlite-wal). Add these two to the project also (in the same directory as the sqlite file). Without them core data throws an error.
Set the NSReadOnlyPersistentStoreOption in persistentStoreDescription (as shown above). Without this you get a warning (possible future fatal error).

Renamed the "Modify By" field after using Elevated Mode

I'm currently facing to an issue using the Elevated Mode used in a Feature.
I have created a custome SharePoint security role (contribute role without the Delete right).
The goal of my SharePoint feature is the following:
When uploading a file to a SP Site, the name of the file needs to be renamed using the meta-data's selected. When uploading a file, a second form is asking the user to defined 3 or 4 meta-data's.
To rename the file, i have developed the following code:
Public override void ItemAdded(SPItemEventProperties properties)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
CallFunctionToUpdate();
});
}
Public override void ItemUpdated(SPItemEventProperties properties)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
CallFunctionToUpdate();
});
}
Public void CallFunctionToUpdate()
{
try
{
this.EventFiringEnabled = false;
using (SPWeb newWeb = newSite.OpenWeb(_properties.RelativeWebUrl))
{
SPListItem item = newWeb.Lists[_properties.ListId].GetItemById(_properties.ListItem.ID);
newFileName = FilenameManagementHelper.GenerateFilename(properties.ListItem);
currentName = properties.ListItem["Name"].ToString();
var extension = Path.GetExtension(currentName);
if (item["Title"] == null || item["Title"].ToString() != newFileName)
{
item["Title"] = newFileName;
item["Editor"] = new SPFieldUserValue(properties.OpenWeb(), properties.OpenWeb().CurrentUser.ID, properties.OpenWeb().CurrentUser.LoginName);
item.SystemUpdate();
}
if (currentName.Substring(0, currentName.Length - extension.Length) != newFileName)
{
SPList list = newWeb.Lists[_properties.List.Title];
string destUrl = list.RootFolder.Url + "/" + newFileName + extension;
SPFile fileToMove = list.Items[_properties.ListItemUniqueId].File;
SPFolder folder = newWeb.GetFolder(list.RootFolder.Url);
byte[] bin = fileToMove.OpenBinary();
folder.Files.Add(destUrl, bin, fileToMove.Properties, true);
fileToMove.Delete(); newWeb.Lists[list.RootFolder.Url].Update();
}
}
}
catch (Exception ex)
{
DocumentDiagnosticService.LogError(CategoryID.Error, string.Format("Error {0} for the file name - {1}", ex.Message, currentName));
}
finally
{
this.EventFiringEnabled = true;
}
}
Before renaming the file name, I'm updating the field (meta-data's) title and Editor. The second step will move the file (with the meta-data's and the history associated to the uploaded file)
I'm using the Elevated Mode because the user with a restricted Security role cannot delete. In the code developed I'm moving the file renamed and deleting the old file uploaded.
I found that approach because I need to keep the versioning. Updating directly the name of the file (like for the title) is not allowed and that's losing the history. Ex: A file will be uploaded, the name of the file will be updated using the Meta-data's. For the first version, there is no issue. Uploading a second file with the same meta-data's as there is already an existing file with the same name, that will generate an error. Using the Files.Add, that will oerride the current file and will keep the history.
My issue in this case: When the user is uploading the file, the fields Title and Editor are correctly replaced. Than is moving the file, renaming the field Name and deleting the old version. At this moment, the Modify by field is coming the SharePoint Sys Admin all the time.
How can i keep the Modifiy by with the name of the person who is uploading the file ?
EDIT:
Using the following code:
SPList list = newWeb.Lists[_properties.List.Title];
string destUrl = list.RootFolder.Url + "/" + newFileName + extension;
SPFile fileToMove = list.Items[_properties.ListItemUniqueId].File;
SPFolder folder = newWeb.GetFolder(list.RootFolder.Url);
byte[] bin = fileToMove.OpenBinary();
folder.Files.Add(destUrl, bin, fileToMove.Properties, true);
fileToMove.Delete();
Allow me to move the file with the meta-data's selected during the upload. I still have the versioning if a current version is already uploaded BUT the Modified By is SysAdmin.
Using the following code:
SPList list = newWeb.Lists[_properties.List.Title];
string destUrl = list.RootFolder.Url + "/" + newFileName + extension;
SPFile fileToMove = list.Items[_properties.ListItemUniqueId].File;
SPFolder folder = newWeb.GetFolder(list.RootFolder.Url);
byte[] bin = fileToMove.OpenBinary();
SPUser author = fileToMove.Author;
folder.Files.Add(destUrl, bin, author, author, DateTime.Now, DateTime.Now);
fileToMove.Delete();
Allow me to move the file and keep the history if i already have a version. I can now get the Modified By field filled by the real user who is uploading and not the SysAdmin BUT I'm losing the meta-data's selected during the upload.
Thank you for your support,
Fix.
Use item.Update() instead of SystemUpdate(). It should retain the identity of logged in user.
Thank you for your support.
I have solved my issue by using the following code:
folder.Files.Add(destUrl, bin, fileToMove.Properties, author, author, DateTime.Now, DateTime.Now, true);
Now, I have the Modified By value filled with the user who is uploading, the meta-data's are still there and the versioning too.

Creating Sharepoint Directory Recurisvely

I am attempting to create a set of folders that comes in from a flat file in the manner of.
X/Y/Z
and I would like to create a directory for each of these but my memory of recursion has got me in knotts.
here is my code can someone advise.
public void CreateDirectory(SPFolderCollection oWeb, string folder)
{
SPFolder theFolder = oWeb.Add(folder);
theFolder.Update();
}
public void FolderCreator(SPWeb oWeb)
{
StreamReader reader = new StreamReader(this.txtFolders.Text);
while (reader.Peek() != -1)
{
string folderLine = reader.ReadLine();
if (folderLine.Contains("/"))
{
SPFolderCollection collection = oWeb.Folders["Documents"].SubFolders[folderLine.Split('/')[0]].SubFolders;
CreateDirectory(collection, folderLine);
}
SPFolderCollection newCollection = oWeb.Folders["Documents"].SubFolders;
CreateDirectory(newCollection, folderLine);
}
}
This does not work I am looking for it to do recrusion so if I pass
ABC/DEF/GHI
and
ABC/DEF
it will go and create the folders appropriately.
But I am stuck as how to do that.
The SPFileCollection.Add() methods allow you to pass in the full relative path of a file. So this may be an option assuming you aren't just generating a folder structure, which you may be doing, in which case this won't really work unless you create a temporary file and then delete it to keep the folder path.
web.Files.Add("/sites/somesite/shared documents/foldera/folderb/folderc/somefile.txt", stream);

How to set URL when a wiki site is created programmatically in SharePoint 2010?

I am creating a new site with:
SPSite currentContext = SPContext.GetContext(HttpContext.Current).Site;
SPWeb parentID = currentContext.OpenWeb(new Guid(parentSiteValue));
newWeb = parentID.Webs.Add(newSiteUrl, newSiteName, null, (uint)1033, siteTemplate, true, false);
siteTemplate is a template I select in a dropdown and it works fine to create sites when I create a site from a team site template or similiar but when a wiki site is created the actual URL is /pages/home.aspx under the parent site but if I add this to newSiteUrl I get errors such as can't have trailing slash, the folder doesn't exist and so on.
How can I create a wiki site and set the url programmatically?
Thanks in advance.
EDIT
set the URL to
newSiteUrl = newSiteName + "/pages/"
gives me
"testpage/pages/" contains leading or trailing slash, which is invalid.
newSiteUrl = newSiteName + "/pages"
The folder that would hold URL '/dept/class/wikitest/pages'
does not exist on the server.
newSiteUrl = newSiteName + "/pages/home.aspx"
The URL '/dept/class/wikitest/pages/home.aspx' is invalid.
It may refer to a nonexistent file or folder,
or refer to a valid file or folder that is not in the current Web.
I've posted an answer to your question here: http://social.technet.microsoft.com/Forums/en-US/sharepoint2010programming/thread/e25f10ef-bdd9-4445-8508-67b58c2396f9 hope this helps!
joel
joelblogs.co.uk
you may set the url in this way:
using (SPSite site = new SPSite("http://localhost"))
{
string parentWebName = "MyOrganization";
using (SPWeb parentWeb = site.OpenWeb())
{
string webTitle = "DepartMent Wiki";
string webDesc = "DepartMent Wiki"; string webName = "HRWiki";
string webUrl = String.Format("{0}/{1}", parentWebName, webName);
uint webLcid = parentWeb.Language;
// Name value for the Document Workspace template.
string webTemplateName = "STS#4";
SPWeb newWeb = null;
// Create the new web.
try
{
newWeb = site.AllWebs.Add(webUrl, webTitle, webDesc, webLcid, webTemplateName, false, false);
SPFolder rootFolder = newWeb.RootFolder;
rootFolder.WelcomePage = "My Wiki Library/MyWelcome.aspx";
rootFolder.Update();
}
catch (ArgumentException ex)
{
}
}
}
hope this help.

MapPath or equivalent to use in an installation application

I need to check a .config file in an installation application (iis custom action in a WIX project). The user picks a website and enters a virtual directory name. I can't do a http read to retrieve the config file as ASP.NET does not serve config files.
How can I find the local disk path of the selected website and virtual directory?
After further searching, I ended up using DirectoryServices. I'm posting my solution here for others.
If there is a better way, please still post it.
static string FindVirtualDirectoryPath(string virtualDirectoryName)
{
return FindVirtualDirectoryPath(null, virtualDirectoryName);
}
static string FindVirtualDirectoryPath(string siteName, string virtualDirectoryName)
{
DirectoryEntry iis = new DirectoryEntry("IIS://localhost/W3SVC");
foreach (DirectoryEntry index in iis.Children)
{
if (index.SchemaClassName == "IIsWebServer")
{
int id = Convert.ToInt32(index.Name);
DirectoryEntry site = new DirectoryEntry(string.Concat("IIS://localhost/W3SVC/", id));
string iSiteName = site.Properties["ServerComment"].Value.ToString();
if (iSiteName == siteName || (string.IsNullOrEmpty(siteName) && id == 1))
{
DirectoryEntry rootVDir = new DirectoryEntry(string.Concat("IIS://localhost/W3SVC/", id, "/Root"));
foreach (DirectoryEntry vDir in rootVDir.Children)
{
if (vDir.SchemaClassName == "IIsWebVirtualDir" && vDir.Name.ToLower() == virtualDirectoryName.ToLower())
{
return vDir.Properties["Path"].Value.ToString();
}
}
}
}
}
return null;
}
Have you tried using the standard WiX IIsExtension for this? Just capture the user input in a property, and then use standard elements like iis:WebSite and iis:WebVirtualDir to create a virtual directory in appropriate web site.

Resources