package org.sakaiproject.component.legacy.content; // import import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.sql.Connection; import java.sql.ResultSet; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Stack; import java.util.Map; import java.util.HashMap; import org.sakaiproject.api.kernel.id.IdManager; import org.sakaiproject.exception.IdUnusedException; import org.sakaiproject.exception.PermissionException; import org.sakaiproject.exception.ServerOverloadException; import org.sakaiproject.exception.TypeException; import org.sakaiproject.service.framework.component.cover.ComponentManager; import org.sakaiproject.service.framework.sql.SqlReader; import org.sakaiproject.service.framework.sql.SqlService; import org.sakaiproject.service.legacy.content.ContentCollection; import org.sakaiproject.service.legacy.content.ContentCollectionEdit; import org.sakaiproject.service.legacy.content.ContentResource; import org.sakaiproject.service.legacy.content.ContentResourceEdit; import org.sakaiproject.service.legacy.content.LockManager; import org.sakaiproject.service.legacy.entity.ResourceProperties; import org.sakaiproject.service.legacy.entity.ResourcePropertiesEdit; import org.sakaiproject.service.legacy.time.Time; import org.sakaiproject.service.legacy.time.cover.TimeService; import org.sakaiproject.util.storage.BaseDbSingleStorage; import org.sakaiproject.util.storage.StorageUser; import org.sakaiproject.util.xml.Xml; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.api.kernel.session.cover.SessionManager; import org.sakaiproject.component.legacy.content.BaseContentService.CollectionStorageUser; import org.sakaiproject.component.legacy.content.BaseContentService.ResourceStorageUser; import org.sakaiproject.component.legacy.content.BaseContentService.Storage; import org.sakaiproject.component.legacy.content.FileSystemManager; import org.sakaiproject.component.legacy.content.DbContentService.DbStorage; import org.sakaiproject.service.framework.log.Logger; import org.sakaiproject.service.framework.session.cover.UsageSessionService; import org.sakaiproject.service.legacy.archive.ArchiveService; import org.sakaiproject.service.legacy.authzGroup.AuthzGroup; import org.sakaiproject.service.legacy.authzGroup.Role; import org.sakaiproject.service.legacy.authzGroup.cover.AuthzGroupService; import org.sakaiproject.service.legacy.site.Site; import org.sakaiproject.service.legacy.site.cover.SiteService; import org.sakaiproject.service.legacy.time.Time; import org.sakaiproject.service.legacy.time.cover.TimeService; import org.sakaiproject.service.legacy.user.User; import org.sakaiproject.service.legacy.user.cover.UserDirectoryService; import org.sakaiproject.service.framework.config.cover.ServerConfigurationService; import org.sakaiproject.service.legacy.entity.ResourceProperties; /** *

UCDavisDbContentService extends DbContentService, which is an extension of the BaseContentService with a database implementation.

*

The sql scripts in src/sql/chef_content.sql must be run on the database.

* */ public class UCDavisDbContentService extends DbContentService { private static Log M_log = LogFactory.getLog(UCDavisDbContentService.class); private static String UCD_AFS_QUOTA_SCRIPT = "/home/samerson/bin/QUOTA-CHECK-TEST.ksh "; private static String UCD_AFS_VOL_DIR_CREATE_SCRIPT = "/home/samerson/bin/VOL-DIR-CREATE.ksh "; private static String SAKAI_INSTANCE_NAME = " smartsite"; //Here add reference to impl of File Storage Mgr (e.g. ours is AFS) protected FileSystemManager fileSystemManager; protected void setFileSystemManager(FileSystemManager fileSystemMgr) { this.fileSystemManager = fileSystemMgr; } protected FileSystemManager getFileSystemManager() { return this.fileSystemManager; } //private String ucdResourceRef; private void getStorageParams() { System.out.println("site quota for Storage impl = " + this.m_siteQuota); System.out.println("collection table name for Storage impl = " + this.m_collectionTableName); System.out.println("body volumes for Storage impl = " + this.getBodyVolumes()); System.out.println("drop box collection for Storage impl = " + this.getDropboxCollection()); } /** inherit all the setter and create getter for the bodyPath from the DbContentHostingService by default */ /**Getter: * Configuration: get the external file system path for body storage * * @param value * The complete path to the root of the external file system storage area for resource body bytes. */ public String getBodyPath(String resourcePath) { String returnBodyPath = null; try { //find current user String curUserId = SessionManager.getCurrentSessionUserId(); System.out.println("Current user from UDService = " + curUserId ); //set base course content path String baseUserContentPath = "/afs/home.ucdavis.edu/home/"; String baseCourseContentPath = "/afs/.ucdavis.edu/app/sakai/class/"; String baseMiscSiteContentPath = "/afs/.ucdavis.edu/app/sakai/misc/"; System.out.println("getBodyPath(): resource reference = " + resourcePath); String refPath = StripResourceReferencePath(resourcePath); String UserIdRef = null; String SiteRef = null; String [] RefSplit = refPath.split("/"); boolean curSiteUserBool = false; boolean userProvided = false; //check if current user id is valid, from session if (curUserId != null) { System.out.println("getBodyPath, user path ? " + refPath.startsWith("/user/")); System.out.println("getBodyPath, project/other path ? " + refPath.startsWith("/group/")); ResourceProperties Props = null; ResourcePropertiesEdit EProps = null; if (refPath.startsWith("/user/")) { UserIdRef = RefSplit[2]; curSiteUserBool = true; System.out.println("Current user id is not null.."); System.out.println("Current user site ref from SiteService=" + UserIdRef ); System.out.println("Is this a user site | " + curSiteUserBool); System.out.println("getBodyPath, this type is a user site (~) = "); //check if user is provided by looking @ property :ucdsakai-externally-provided, which is determined when UserObject is created, via UserDirProvider impl User userRef = UserDirectoryService.getUser(UserIdRef); try{ Props = userRef.getProperties(); if (Props.getProperty("ucdsakai-externally-provided").equalsIgnoreCase("1")) { userProvided = true; } } catch (Exception prope) { prope.printStackTrace(); System.out.println("getUser attempt to add externally provided property failed"); } if (userProvided) { String userAFSVolumeHead = (String)FindAFSVolumeMapping(UserIdRef,"user").get("AFSVolumeHead"); String UContentPath = baseUserContentPath + userAFSVolumeHead; try{ EProps = (ResourcePropertiesEdit)(Props); EProps.addProperty("AFSVol", UserIdRef); System.out.println("getting user AFS property after set=" + EProps.getProperty("AFSVol")); } catch (Exception aab) { System.out.println("Testing Resource Properties edit on user volume create"); aab.printStackTrace(); } String UVolPath = UContentPath + "/" + UserIdRef + "/.sakai" + "/" + SAKAI_INSTANCE_NAME; CheckIfVolumeExistsInAFS(UVolPath,"user"); returnBodyPath = UVolPath; } else { String UContentPath = baseUserContentPath; returnBodyPath = UContentPath + "/ucdsakai-internal-accounts/" + UserIdRef + "/.sakai" + "/" + SAKAI_INSTANCE_NAME;; } } else if (refPath.startsWith("/group/")) { SiteRef = RefSplit[2]; System.out.println("site ref from SiteService, starts with group, =" + SiteRef ); Site curSite = SiteService.getSite(SiteRef); if (curSite.getType().equalsIgnoreCase("course")) { String AFSCourseVols = baseCourseContentPath + curSite.getProviderGroupId() + "/" + SAKAI_INSTANCE_NAME + "/" + curSite.getId(); try{ EProps = (ResourcePropertiesEdit)(Props); EProps.addProperty("AFSVol", (String)FindAFSVolumeMapping(SiteRef,"course").get("AFSVolume")); System.out.println("getting course AFS property after set=" + EProps.getProperty("AFSVol")); } catch (Exception eCourse) { System.out.println("Error: Resource Properties edit on course volume create"); eCourse.printStackTrace(); } CheckIfVolumeExistsInAFS(AFSCourseVols,curSite.getType()); System.out.println("AFSCourseVols bodyPath = " + AFSCourseVols); returnBodyPath = AFSCourseVols; } else { String AFSMiscSiteVols = baseMiscSiteContentPath + "/" + SAKAI_INSTANCE_NAME + curSite.getType() + "/" + SiteRef; try{ EProps = (ResourcePropertiesEdit)(Props); EProps.addProperty("AFSVol", (String)FindAFSVolumeMapping(SiteRef,"misc").get("AFSVolume")); System.out.println("getting misc AFS property after set=" + EProps.getProperty("AFSVol")); } catch (Exception eMisc) { System.out.println("Error: Resource Properties edit on misc volume create"); eMisc.printStackTrace(); } CheckIfVolumeExistsInAFS(AFSMiscSiteVols,curSite.getType()); returnBodyPath = AFSMiscSiteVols; } } } }//end try catch (Exception bp) { bp.printStackTrace(); returnBodyPath = null; } return returnBodyPath; } /**Override: * Configuration: set the external file system path for body storage If set, the resource binary database table will not be used. * * @param value * The complete path to the root of the external file system storage area for resource body bytes. */ public void setBodyPath(String value) { System.out.println("setBodyPath: setting body path value to = " + value); this.m_bodyPath = value; } public String getBodyVolumes() { try { String returnBodyVolumes = "ucdsakai"; String curUserId = SessionManager.getCurrentSessionUserId(); if (curUserId != null) { String curSiteId = SiteService.getUserSiteId(curUserId); Site curSite = SiteService.getSite(curSiteId); System.out.println("getBodyVolumes: Current site from SiteService, on BodyVolume get = " + curSiteId ); boolean curSiteUserBool = SiteService.isUserSite(curSiteId); if (curSiteUserBool) { System.out.println("getBodyVolumes: this type is a user site, getting body Volumes"); returnBodyVolumes = (String)FindAFSVolumeMapping(curUserId,"user").get("AFSVolumeHead"); } } return returnBodyVolumes; } catch (Throwable t) { return null; } } /**Override: * Form the full file path+name used to store the resource body in an external file system. * @param resource The resource. * @return The resource external file name. */ protected String externalResourceFileName(ContentResource resource) { //get reference path in form of /content/usr/.. or /content/group/.. String ucdResourceRef = ((BaseResourceEdit) resource).getReference(); System.out.println("externalResourceFileName: getBodyPath() = " + getBodyPath(ucdResourceRef)); System.out.println("externalResourceFileName: m_filePath = " + ((BaseResourceEdit) resource).m_filePath); System.out.println("externalResourceFileName: resource reference = " + ((BaseResourceEdit) resource).getReference()); System.out.println("externalResourceFileName reference root for siteservice = " + SiteService.REFERENCE_ROOT); System.out.println("externalResourceFileName return = " + getBodyPath(ucdResourceRef) + ((BaseResourceEdit) resource).m_filePath); return getBodyPath(ucdResourceRef) + ((BaseResourceEdit) resource).m_filePath; } protected Map FindAFSVolumeMapping(String currEntityId,String type) { Map AFSVolumeMapping = new HashMap(); String AFSvolhead = null; if (type.equalsIgnoreCase("user")) { System.out.println("FindAFSVolume: currEntityId (user)=" + currEntityId); int currUserIdlen = currEntityId.trim().length(); //System.out.println("find first char: " + currEntityId.toLowerCase().trim().substring(0,1)); //System.out.println("find last char: " + currEntityId.toLowerCase().trim().substring(currUserIdlen-1,currUserIdlen)); AFSvolhead = currEntityId.toLowerCase().trim().substring(0,1) + currEntityId.toLowerCase().trim().substring(currUserIdlen-1,currUserIdlen); AFSVolumeMapping.put("AFSVolumeHead", AFSvolhead); AFSVolumeMapping.put("AFSVolume", currEntityId); System.out.println("FindAFSVolume map length: returnAFSvol size =" + AFSVolumeMapping.size()); } else if (type.equalsIgnoreCase("course")) { return null; } else { return null; } return (AFSVolumeMapping); } private String StripResourceReferencePath(String fullRefPath) { StringBuffer pathname = new StringBuffer(fullRefPath); int lenFullRefPath = fullRefPath.length(); pathname.delete(1,9); pathname.delete(pathname.lastIndexOf("/"),lenFullRefPath); System.out.println("StripResourceReferencePath: remaining string=" + pathname); return pathname.toString(); } public void CheckIfVolumeExistsInAFS(String VolToCheck,String VolType) { System.out.println("Volume checking" + VolToCheck); String execVolCreateScript = null; String execQuotaScript = null; InputStream input = null; InputStream errorInput = null; InputStream input2 = null; InputStream errorInput2 = null; Process proc = null; Process proc2 = null; try { if (VolType.equalsIgnoreCase("user")) { execVolCreateScript = UCD_AFS_VOL_DIR_CREATE_SCRIPT + VolToCheck + " user " + SAKAI_INSTANCE_NAME; execQuotaScript = UCD_AFS_QUOTA_SCRIPT + VolToCheck + " user " + SAKAI_INSTANCE_NAME; } else if (VolType.equalsIgnoreCase("course")) { execVolCreateScript = UCD_AFS_VOL_DIR_CREATE_SCRIPT + VolToCheck + " course " + SAKAI_INSTANCE_NAME; execQuotaScript = UCD_AFS_QUOTA_SCRIPT + VolToCheck + " course " + SAKAI_INSTANCE_NAME; } else if (VolType.equalsIgnoreCase("project")) { execVolCreateScript = UCD_AFS_VOL_DIR_CREATE_SCRIPT + VolToCheck + " userproject " + SAKAI_INSTANCE_NAME; execQuotaScript = UCD_AFS_QUOTA_SCRIPT + VolToCheck + " userproject " + SAKAI_INSTANCE_NAME; } else { execVolCreateScript = UCD_AFS_VOL_DIR_CREATE_SCRIPT + VolToCheck + " misc " + SAKAI_INSTANCE_NAME; execQuotaScript = UCD_AFS_QUOTA_SCRIPT + VolToCheck + " misc " + SAKAI_INSTANCE_NAME; } Runtime rt= Runtime.getRuntime(); proc= rt.exec(execVolCreateScript); proc2= rt.exec(execQuotaScript); //wait for process to stop proc.waitFor(); proc2.waitFor(); input = proc.getInputStream(); errorInput = proc.getErrorStream(); input2 = proc2.getInputStream(); errorInput2 = proc2.getErrorStream(); } catch (Exception e) { e.printStackTrace(); } //check if error streams are present try{ int count = input.available() + input2.available(); int eCount = errorInput.available() + errorInput2.available(); //check for error output if (eCount > 0) { byte[] bufferE = new byte[eCount]; errorInput.read(bufferE); String stdError = new String(bufferE); System.out.println("Standard Error Output:"); System.out.println(stdError); } else { System.out.println("No Standard Error Output found"); } //check for std output if (count > 0) { byte[] bufferO = new byte[count]; input.read(bufferO); String stdOut = new String(bufferO); System.out.println("Standard Output:"); System.out.println(stdOut); } else { System.out.println("No Standard Output found"); } } catch (Exception be) { System.out.println("Error getting output returned from shell script"); } System.out.println("script finished, with exit code=" + proc.exitValue()); } public int CheckVolumeQuota(String volToCheck,int resourceLen) { System.out.println("Checking quota on: " + volToCheck); String execString = null; InputStream input = null; InputStream errorInput = null; Process proc = null; try { execString = UCD_AFS_QUOTA_SCRIPT + volToCheck; Runtime rt= Runtime.getRuntime(); proc= rt.exec(execString); //wait for process to stop proc.waitFor(); input = proc.getInputStream(); errorInput = proc.getErrorStream(); } catch (Exception e) { e.printStackTrace(); } //check if error streams are present try{ int count = input.available(); int eCount = errorInput.available(); //check for error output if (eCount > 0) { byte[] bufferE = new byte[eCount]; errorInput.read(bufferE); String stdError = new String(bufferE); System.out.println("Quota Standard Error Output:"); System.out.println(stdError); } else { System.out.println("No Standard Error Output found"); } //check for std output if (count > 0) { byte[] bufferO = new byte[count]; input.read(bufferO); String stdOut = new String(bufferO); System.out.println("Quota Standard Output:"); System.out.println(stdOut); } else { System.out.println("No Standard Output found"); } } catch (Exception be) { System.out.println("Error getting output returned from quota shell script"); } System.out.println("quota script finished, with exit value=" + proc.exitValue()); return proc.exitValue(); } /** * Construct a Storage object. * @return The new storage object. */ protected Storage newStorage() { return new DbStorage(new CollectionStorageUser(), new ResourceStorageUser(), (m_bodyPath != null)); } // newStorage /******************************************************************************* * Storage implementation *******************************************************************************/ protected class DbStorage extends DbContentService.DbStorage implements Storage { public DbStorage(StorageUser collectionUser, StorageUser resourceUser, boolean bodyInFile) { super(collectionUser, resourceUser, bodyInFile); } /** * Write the resource body to the external file system. * The file name is the m_bodyPath with the resource id appended. * @param resource The resource whose body is being written. * @param body The body bytes to write. * If there is no body or the body is zero bytes, no entry is inserted into the filesystem. */ protected boolean putResourceBodyFilesystem(ContentResourceEdit resource, byte[] body) { // Do not create the files for resources with zero length bodies if ((body == null) || (body.length == 0)) return true; // form the file name File file = new File(externalResourceFileName(resource)); //perform a check on body length before attempting to save content in the file system //this will assure that quota is extended prior to any failure attempts System.out.println("checking quota, failed attempt:" + CheckVolumeQuota("/afs/home.ucdavis.edu/home/sn/samerson",body.length)); // delete the old if (file.exists()) { file.delete(); } // add the new try { // make sure all directories are there File container = file.getParentFile(); System.out.println("xxxxA: path to parent file=" + container.getPath()); if (container != null) { System.out.println("xxxxA: trying to make dirs=yes"); container.mkdirs(); } // write the file FileOutputStream out = new FileOutputStream(file); out.write(body); out.close(); } catch (Throwable t) { System.out.println("failed attempt to write resource: quota check via CheckQuota api=" + CheckVolumeQuota("/afs/home.ucdavis.edu/home/sn/samerson",body.length)); m_logger.warn(this + ": failed to write resource: " + resource.getId() + " : " + t); return false; } return true; } } } //UCDavisDbContentService