package fr.itldev.koya.alfservice; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.alfresco.model.ContentModel; import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException; import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.apache.log4j.Logger; import fr.itldev.koya.exception.KoyaServiceException; import fr.itldev.koya.model.KoyaModel; import fr.itldev.koya.model.exceptions.KoyaErrorCodes; import fr.itldev.koya.model.impl.Company; import fr.itldev.koya.model.impl.CompanyProperties; import fr.itldev.koya.model.impl.Contact; import fr.itldev.koya.model.impl.ContactItem; import fr.itldev.koya.model.impl.GeoPos; public class CompanyPropertiesService { private static final String XPATH_DEFAULTCOMPANY_LOGO = "//app:company_home/app:dictionary/cm:koya/cm:default-company/cm:company.properties/cm:logo.png"; private static final String COMPANYPROPERTIES_FILE_NAME = "company.properties"; protected static final String KOYA_CONFIG = "koya-config"; private static final Set<QName> QNAMEFILTER_CONTACTITEM = new HashSet<QName>() { { add(KoyaModel.TYPE_CONTACTITEM); } }; private static final Set<QName> QNAMEFILTER_CONTACT = new HashSet<QName>() { { add(KoyaModel.TYPE_CONTACT); } }; private NodeRef defaultLogo; private final Logger logger = Logger .getLogger(CompanyPropertiesService.class); protected KoyaNodeService koyaNodeService; protected SearchService searchService; protected NodeService nodeService; protected ContentService contentService; protected UserService userService; protected FileFolderService fileFolderService; protected NodeService unprotNodeService; public void setKoyaNodeService(KoyaNodeService koyaNodeService) { this.koyaNodeService = koyaNodeService; } public void setSearchService(SearchService searchService) { this.searchService = searchService; } public void setNodeService(NodeService nodeService) { this.nodeService = nodeService; } public void setContentService(ContentService contentService) { this.contentService = contentService; } public void setUserService(UserService userService) { this.userService = userService; } public void setFileFolderService(FileFolderService fileFolderService) { this.fileFolderService = fileFolderService; } public void setUnprotNodeService(NodeService unprotNodeService) { this.unprotNodeService = unprotNodeService; } public NodeRef getLogo(String companyShortName) throws KoyaServiceException { return getLogo(koyaNodeService.companyBuilder(companyShortName)); } /** * * @param c * @return */ public NodeRef getLogo(Company c) { // search in company koya-config dir a logo NodeRef companyPropertiesNodeRef = (NodeRef) nodeService.getProperty( c.getNodeRef(), KoyaModel.PROP_COMPANYHOME); List<AssociationRef> logos = nodeService.getTargetAssocs( companyPropertiesNodeRef, KoyaModel.ASSOC_LOGO_COMPANY); if (logos.size() == 1) { // retrieve company property current logo return logos.get(0).getTargetRef(); } else { // if (logos.size() > 1) { logger.warn("logo config error : many logo association for company " + c.getName()); } } return getDefaultLogo(); } private NodeRef getDefaultLogo() { if (defaultLogo == null) { ResultSet rs = null; try { rs = searchService .query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, SearchService.LANGUAGE_XPATH, XPATH_DEFAULTCOMPANY_LOGO); if (rs.getNumberFound() == 1) { defaultLogo = rs.getNodeRef(0); } else { logger.warn("No company logo or koya default logo found : please check repository defaults settings"); } } finally { if (rs != null) { rs.close(); } } } return defaultLogo; } /** * Replaces current company logo with uploaded one Files have no name to * avoid duplicates.filenames are stored in title. Updates company * * @throws KoyaServiceException */ public Map<String, String> uploadNewLogo(NodeRef companyPropertiesNode, String fileName, org.springframework.extensions.surf.util.Content content) throws KoyaServiceException { // TODO check duplicate content /** * Create Node */ final NodeRef createdNode; try { final Map<QName, Serializable> properties = new HashMap<>(); properties.put(ContentModel.PROP_TITLE, fileName); ChildAssociationRef car = nodeService.createNode( companyPropertiesNode, ContentModel.ASSOC_CONTAINS, QName .createQName( NamespaceService.CONTENT_MODEL_1_0_URI, fileName),// TODO changer name ContentModel.TYPE_CONTENT, properties); createdNode = car.getChildRef(); } catch (DuplicateChildNodeNameException dcne) { throw new KoyaServiceException( KoyaErrorCodes.FILE_UPLOAD_NAME_EXISTS, fileName); } /** * Add Content to created node * */ ContentWriter writer = this.contentService.getWriter(createdNode, ContentModel.PROP_CONTENT, true); if (content.getMimetype() != null) { writer.setMimetype(content.getMimetype()); } else { writer.guessMimetype(fileName); } if (content.getEncoding() != null) { writer.setEncoding(content.getEncoding()); } writer.guessEncoding(); writer.putContent(content.getInputStream()); /** * Update logo reference */ List<AssociationRef> logos = nodeService.getTargetAssocs( companyPropertiesNode, KoyaModel.ASSOC_LOGO_COMPANY); if (logos.size() == 0) { // create association nodeService.createAssociation(companyPropertiesNode, createdNode, KoyaModel.ASSOC_LOGO_COMPANY); } else if (logos.size() == 1) { // update association nodeService.setAssociations(companyPropertiesNode, KoyaModel.ASSOC_LOGO_COMPANY, new ArrayList<NodeRef>() { { add(createdNode); } }); } else { // shouldn't happen logger.warn("many logo association found on company properties node " + companyPropertiesNode); } Map<String, String> retMap = new HashMap<>(); retMap.put("filename", fileName); retMap.put("originalFilename", fileName); retMap.put("rename", Boolean.FALSE.toString()); retMap.put("size", Long.toString(writer.getSize())); return retMap; } public CompanyProperties getProperties(String shortName) throws KoyaServiceException { return getProperties(koyaNodeService.companyBuilder(shortName)); } /** * Get Company properties. * * @param companyName * @return * @throws fr.itldev.koya.exception.KoyaServiceException */ public CompanyProperties getProperties(Company c) throws KoyaServiceException { NodeRef companyPropertiesNodeRef = (NodeRef) nodeService.getProperty( c.getNodeRef(), KoyaModel.PROP_COMPANYHOME); CompanyProperties cp = new CompanyProperties(c.getName(), companyPropertiesNodeRef); if (companyPropertiesNodeRef == null) { this.createCompanyConfigFile(c); } if (companyPropertiesNodeRef != null) { cp.setNodeRef(companyPropertiesNodeRef); cp.setTitle(c.getTitle()); // address, description,legal informations - company properties // attributes cp.setAddress((String) nodeService.getProperty( companyPropertiesNodeRef, KoyaModel.PROP_ADDRESS)); cp.setAddress2((String) nodeService.getProperty( companyPropertiesNodeRef, KoyaModel.PROP_ADDRESS2)); cp.setZipCode((String) nodeService.getProperty( companyPropertiesNodeRef, KoyaModel.PROP_ZIPCODE)); cp.setCity((String) nodeService.getProperty( companyPropertiesNodeRef, KoyaModel.PROP_CITY)); cp.setDescription((String) nodeService.getProperty( companyPropertiesNodeRef, KoyaModel.PROP_DESCRIPTION)); cp.setLegalInformations((String) nodeService.getProperty( companyPropertiesNodeRef, KoyaModel.PROP_LEGALINFOS)); cp.setMailHeaderText((String) nodeService.getProperty( companyPropertiesNodeRef, KoyaModel.PROP_MAILHEADERTEXT)); // if geographic aspect is set, get latitude and longitude if (nodeService.hasAspect(companyPropertiesNodeRef, ContentModel.ASPECT_GEOGRAPHIC)) { cp.setGeoPos(new GeoPos((Double) nodeService.getProperty( companyPropertiesNodeRef, ContentModel.PROP_LATITUDE), (Double) nodeService.getProperty( companyPropertiesNodeRef, ContentModel.PROP_LONGITUDE))); } // load contact items cp.setContactItems(loadContactItems(companyPropertiesNodeRef)); // load contacts cp.setContacts(loadContacts(companyPropertiesNodeRef)); } return cp; } private List<ContactItem> loadContactItems(NodeRef parent) { List<ContactItem> contactItems = new ArrayList<ContactItem>(); // TODO cibler recherche par type for (ChildAssociationRef car : nodeService.getChildAssocs(parent, QNAMEFILTER_CONTACTITEM)) { NodeRef currentNodeRef = car.getChildRef(); try { ContactItem companyCi = new ContactItem(currentNodeRef); companyCi.setValue((String) nodeService.getProperty( currentNodeRef, KoyaModel.PROP_CONTACTITEM_VALUE)); companyCi.setType(Integer.valueOf((String) nodeService .getProperty(currentNodeRef, KoyaModel.PROP_CONTACTITEM_TYPE))); contactItems.add(companyCi); } catch (NumberFormatException | InvalidNodeRefException ex) { // silent exception catching : if error occurs no // contact created } } return contactItems; } public List<Contact> loadContacts(NodeRef parent) { List<Contact> contacts = new ArrayList<Contact>(); for (ChildAssociationRef car : nodeService.getChildAssocs(parent, QNAMEFILTER_CONTACT)) { NodeRef contactNodeRef = car.getChildRef(); Contact contact = new Contact(contactNodeRef); contact.setTitle((String) nodeService.getProperty(contactNodeRef, ContentModel.PROP_TITLE)); // ========= get associated user informations List<AssociationRef> assocRefs = nodeService.getTargetAssocs( contactNodeRef, KoyaModel.ASSOC_CONTACT_USER); // there must be exactly one associated user //TODO ensure unicity // in the model if (assocRefs.size() != 1) { logger.error("Error retrieving contact asociated user : skip" + assocRefs.size()); break; } contact.setUser(userService.buildUser(assocRefs.get(0) .getTargetRef())); contact.setContactItems(loadContactItems(contactNodeRef)); contacts.add(contact); } return contacts; } /** * * @param companyName * @param compProperties * @throws KoyaServiceException */ public void commitProperties(String companyName, CompanyProperties cp) throws KoyaServiceException { Company c = koyaNodeService.companyBuilder(companyName); NodeRef companyPropertiesNodeRef = (NodeRef) nodeService.getProperty( c.getNodeRef(), KoyaModel.PROP_COMPANYHOME); // Modify company Title nodeService.setProperty(c.getNodeRef(), ContentModel.PROP_TITLE, cp.getTitle()); /** * Merge commited CompanyProperties argument with * companyPropertiesNodeRef */ nodeService.setProperty(companyPropertiesNodeRef, KoyaModel.PROP_ADDRESS, cp.getAddress()); nodeService.setProperty(companyPropertiesNodeRef, KoyaModel.PROP_ADDRESS2, cp.getAddress2()); nodeService.setProperty(companyPropertiesNodeRef, KoyaModel.PROP_ZIPCODE, cp.getZipCode()); nodeService.setProperty(companyPropertiesNodeRef, KoyaModel.PROP_CITY, cp.getCity()); nodeService.setProperty(companyPropertiesNodeRef, KoyaModel.PROP_DESCRIPTION, cp.getDescription()); nodeService.setProperty(companyPropertiesNodeRef, KoyaModel.PROP_LEGALINFOS, cp.getLegalInformations()); nodeService.setProperty(companyPropertiesNodeRef, KoyaModel.PROP_MAILHEADERTEXT, cp.getMailHeaderText()); // merge geopos object if (cp.getGeoPos() != null) { // TODO geopos remove policy if (!nodeService.hasAspect(companyPropertiesNodeRef, ContentModel.ASPECT_GEOGRAPHIC)) { nodeService.addAspect(companyPropertiesNodeRef, ContentModel.ASPECT_GEOGRAPHIC, null); } nodeService.setProperty(companyPropertiesNodeRef, ContentModel.PROP_LATITUDE, cp.getGeoPos().getLatitude()); nodeService.setProperty(companyPropertiesNodeRef, ContentModel.PROP_LONGITUDE, cp.getGeoPos().getLongitude()); } mergeContactItems(companyPropertiesNodeRef, cp.getContactItems()); mergeContacts(companyPropertiesNodeRef, cp.getContacts()); } private void mergeContactItems(NodeRef parentNode, List<ContactItem> contactItems) { // merge contact item List<ContactItem> existingContactItems = new ArrayList<ContactItem>(); for (ChildAssociationRef car : nodeService.getChildAssocs(parentNode, QNAMEFILTER_CONTACTITEM)) { existingContactItems.add(new ContactItem(car.getChildRef())); } // cp.getContactItems() --> contacts items to modify or create for (final ContactItem ci : contactItems) { // update existing node if (ci.getNodeRef() != null) { existingContactItems.remove(ci); // update contactitem nodeService.setProperty(ci.getNodeRef(), KoyaModel.PROP_CONTACTITEM_TYPE, ci.getType()); nodeService.setProperty(ci.getNodeRef(), KoyaModel.PROP_CONTACTITEM_VALUE, ci.getValue()); } else { Map<QName, Serializable> props = new HashMap<QName, Serializable>() { { put(KoyaModel.PROP_CONTACTITEM_TYPE, ci.getType()); put(KoyaModel.PROP_CONTACTITEM_VALUE, ci.getValue()); } }; // create new node nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName( NamespaceService.CONTENT_MODEL_1_0_URI, ci.getValue()), KoyaModel.TYPE_CONTACTITEM, props); } } // delete removed contact items (ie exists on disk but not in commited // object) for (ContactItem cDel : existingContactItems) { nodeService.deleteNode(cDel.getNodeRef()); } } private void mergeContacts(NodeRef parentNode, List<Contact> contacts) { // merge contact item List<Contact> existingContacts = new ArrayList<Contact>(); for (ChildAssociationRef car : nodeService.getChildAssocs(parentNode, QNAMEFILTER_CONTACT)) { existingContacts.add(new Contact(car.getChildRef())); } for (final Contact c : contacts) { // associated user String personName = (String) nodeService.getProperty(c.getUser() .getNodeRef(), ContentModel.PROP_USERNAME); // update existing node if (c.getNodeRef() != null) { existingContacts.remove(c); List<AssociationRef> assocRefs = nodeService.getTargetAssocs( c.getNodeRef(), KoyaModel.ASSOC_CONTACT_USER); if (assocRefs.size() == 0) { // create association nodeService .createAssociation(c.getNodeRef(), c.getUser() .getNodeRef(), KoyaModel.ASSOC_CONTACT_USER); } else if (assocRefs.size() == 1) { // update association nodeService.setAssociations(c.getNodeRef(), KoyaModel.ASSOC_CONTACT_USER, new ArrayList<NodeRef>() { { add(c.getUser().getNodeRef()); } }); } else { // shouldn't happen logger.warn("Error retrieving contact asociated user : skip " + c.getNodeRef()); break; } // update contact items values mergeContactItems(c.getNodeRef(), c.getContactItems()); } else { Map<QName, Serializable> props = new HashMap<QName, Serializable>(); props.put(ContentModel.PROP_TITLE, (String) nodeService .getProperty(c.getUser().getNodeRef(), ContentModel.PROP_EMAIL)); // create new contact NodeRef contactCreated = nodeService.createNode( parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName( NamespaceService.CONTENT_MODEL_1_0_URI, personName), KoyaModel.TYPE_CONTACT, props) .getChildRef(); nodeService.createAssociation(contactCreated, c.getUser() .getNodeRef(), KoyaModel.ASSOC_CONTACT_USER); // update contact items values mergeContactItems(contactCreated, c.getContactItems()); } } // delete removed contacts (ie exists on disk but not in commited // object) for (Contact cDel : existingContacts) { nodeService.deleteNode(cDel.getNodeRef()); } } public NodeRef createCompanyConfigFile(Company c) { // TODO Read From company Home variable FileInfo fi = fileFolderService.create( getKoyaConfigNodeRef(c.getNodeRef(), true), COMPANYPROPERTIES_FILE_NAME, KoyaModel.TYPE_COMPANYPROPERTIES); return fi.getNodeRef(); } /** * Return the "koya-config" noderef under the given root. Optionally create * the folder if it does not exist yet. NOTE: must only be set to create if * within a WRITE transaction context. * <p> * Adds the "isIndexed = false" property to the koya-config folder node. * * @param rootRef * Root node reference where the "koya-config" folder should live * @param create * True to create the folder if missing, false otherwise * * @return koya-config folder ref if found, null otherwise if not creating */ protected NodeRef getKoyaConfigNodeRef(final NodeRef rootRef, final boolean create) { NodeRef koyaConfigRef = this.unprotNodeService.getChildByName(rootRef, ContentModel.ASSOC_CONTAINS, KOYA_CONFIG); if (create && koyaConfigRef == null) { if (logger.isDebugEnabled()) { logger.debug("'koya-config' folder not found under path, creating..."); } QName assocQName = QName.createQName( NamespaceService.CONTENT_MODEL_1_0_URI, KOYA_CONFIG); Map<QName, Serializable> properties = new HashMap<>(1, 1.0f); properties.put(ContentModel.PROP_NAME, (Serializable) KOYA_CONFIG); ChildAssociationRef ref = this.unprotNodeService.createNode( rootRef, ContentModel.ASSOC_CONTAINS, assocQName, ContentModel.TYPE_FOLDER, properties); koyaConfigRef = ref.getChildRef(); // koya-config needs to be hidden - applies index control aspect as // part of the hidden aspect Map<QName, Serializable> props = new HashMap<>(); props.put(ContentModel.PROP_IS_INDEXED, Boolean.FALSE); props.put(ContentModel.PROP_IS_CONTENT_INDEXED, Boolean.FALSE); nodeService.addAspect(ref.getChildRef(), ContentModel.ASPECT_INDEX_CONTROL, props); } return koyaConfigRef; } }