@Test public void testReadOnlyEntryFromMultidirectory() throws Exception { MultiDirectory readonlyMultidir = (MultiDirectory) directoryService.getDirectory("readonlymulti"); MultiDirectorySession readonlyDir = (MultiDirectorySession) readonlyMultidir.getSession(); // all should be readonly assertTrue(BaseSession.isReadOnlyEntry(readonlyDir.getEntry("1"))); assertTrue(BaseSession.isReadOnlyEntry(readonlyDir.getEntry("2"))); assertTrue(BaseSession.isReadOnlyEntry(readonlyDir.getEntry("3"))); assertTrue(BaseSession.isReadOnlyEntry(readonlyDir.getEntry("4"))); }
private static void updateSubDirectoryEntry( SubDirectoryInfo dirInfo, Map<String, Object> fieldMap, String id, boolean canCreateIfOptional) { DocumentModel dirEntry = dirInfo.getSession().getEntry(id); if (dirInfo.getSession().isReadOnly() || (dirEntry != null && isReadOnlyEntry(dirEntry))) { return; } if (dirEntry == null && !canCreateIfOptional) { // entry to update doesn't belong to this directory return; } Map<String, Object> map = new HashMap<String, Object>(); map.put(dirInfo.idField, id); for (Entry<String, String> e : dirInfo.fromSource.entrySet()) { map.put(e.getValue(), fieldMap.get(e.getKey())); } if (map.size() > 1) { if (canCreateIfOptional && dirInfo.isOptional && dirEntry == null) { // if entry does not exist, create it dirInfo.getSession().createEntry(map); } else { final DocumentModel entry = BaseSession.createEntryModel(null, dirInfo.dirSchemaName, id, null); // Do not set dataModel values with constructor to force fields // dirty entry.getDataModel(dirInfo.dirSchemaName).setMap(map); dirInfo.getSession().updateEntry(entry); } } }
private static DirectoryEntry getDirectoryEntryFromNode( JsonNode propertiesNode, Directory directory) throws DirectoryException, IOException { String schema = directory.getSchema(); String id = propertiesNode.get(directory.getIdField()).getTextValue(); try (Session session = directory.getSession()) { DocumentModel entry = session.getEntry(id); if (entry == null) { entry = BaseSession.createEntryModel(null, schema, id, new HashMap<>()); } Properties props = new Properties(); Iterator<Entry<String, JsonNode>> fields = propertiesNode.getFields(); while (fields.hasNext()) { Entry<String, JsonNode> fieldEntry = fields.next(); props.put(schema + ":" + fieldEntry.getKey(), fieldEntry.getValue().getTextValue()); } DocumentHelper.setProperties(null, entry, props); return new DirectoryEntry(directory.getName(), entry); } }
@Override public DocumentModel getEntry(String id, boolean fetchReferences) throws DirectoryException { if (!isCurrentUserAllowed(SecurityConstants.READ)) { return null; } init(); String entryId = id; source_loop: for (SourceInfo sourceInfo : sourceInfos) { boolean isReadOnlyEntry = true; final Map<String, Object> map = new HashMap<String, Object>(); for (SubDirectoryInfo dirInfo : sourceInfo.subDirectoryInfos) { final DocumentModel entry = dirInfo.getSession().getEntry(id, fetchReferences); boolean isOptional = dirInfo.isOptional; if (entry == null && !isOptional) { // not in this source continue source_loop; } if (entry != null && !isReadOnlyEntry(entry)) { // set readonly to false if at least one source is writable isReadOnlyEntry = false; } if (entry == null && isOptional && !dirInfo.getSession().isReadOnly()) { // set readonly to false if null entry is from optional and writable directory isReadOnlyEntry = false; } if (entry != null && entry.getId() == null) { entryId = entry.getId(); } for (Entry<String, String> e : dirInfo.toSource.entrySet()) { if (entry != null) { try { map.put(e.getValue(), entry.getProperty(dirInfo.dirSchemaName, e.getKey())); } catch (PropertyException e1) { throw new DirectoryException(e1); } } else { // fill with default values for this directory if (!map.containsKey(e.getValue())) { map.put(e.getValue(), dirInfo.defaultEntry.get(e.getKey())); } } } } // force the entry in readonly if it's defined on the multidirectory if (isReadOnly()) { isReadOnlyEntry = true; } // ok we have the data try { return BaseSession.createEntryModel(null, schemaName, entryId, map, isReadOnlyEntry); } catch (PropertyException e) { throw new DirectoryException(e); } } return null; }
@Test public void testCreateFromModel() throws Exception { String schema = "schema3"; DocumentModel entry = BaseSession.createEntryModel(null, schema, null, null); entry.setProperty("schema3", "uid", "yo"); assertNull(dir.getEntry("yo")); dir.createEntry(entry); assertNotNull(dir.getEntry("yo")); // create one with existing same id, must fail entry.setProperty("schema3", "uid", "1"); try { entry = dir.createEntry(entry); fail("Should raise an error, entry already exists"); } catch (DirectoryException e) { } }
@Override @SuppressWarnings("boxing") public DocumentModelList query( Map<String, Serializable> filter, Set<String> fulltext, Map<String, String> orderBy, boolean fetchReferences) { // list of entries final DocumentModelList results = new DocumentModelListImpl(); if (!isCurrentUserAllowed(SecurityConstants.READ)) { return results; } init(); // entry ids already seen (mapped to the source name) final Map<String, String> seen = new HashMap<String, String>(); if (fulltext == null) { fulltext = Collections.emptySet(); } Set<String> readOnlyEntries = new HashSet<String>(); for (SourceInfo sourceInfo : sourceInfos) { // accumulated map for each entry final Map<String, Map<String, Object>> maps = new HashMap<String, Map<String, Object>>(); // number of dirs seen for each entry final Map<String, Integer> counts = new HashMap<String, Integer>(); // list of optional dirs where filter matches default values List<SubDirectoryInfo> optionalDirsMatching = new ArrayList<SubDirectoryInfo>(); for (SubDirectoryInfo dirInfo : sourceInfo.subDirectoryInfos) { // compute filter final Map<String, Serializable> dirFilter = new HashMap<String, Serializable>(); for (Entry<String, Serializable> e : filter.entrySet()) { final String fieldName = dirInfo.fromSource.get(e.getKey()); if (fieldName == null) { continue; } dirFilter.put(fieldName, e.getValue()); } if (dirInfo.isOptional) { // check if filter matches directory default values boolean matches = true; for (Map.Entry<String, Serializable> dirFilterEntry : dirFilter.entrySet()) { Object defaultValue = dirInfo.defaultEntry.get(dirFilterEntry.getKey()); Object filterValue = dirFilterEntry.getValue(); if (defaultValue == null && filterValue != null) { matches = false; } else if (defaultValue != null && !defaultValue.equals(filterValue)) { matches = false; } } if (matches) { optionalDirsMatching.add(dirInfo); } } // compute fulltext Set<String> dirFulltext = new HashSet<String>(); for (String sourceFieldName : fulltext) { final String fieldName = dirInfo.fromSource.get(sourceFieldName); if (fieldName != null) { dirFulltext.add(fieldName); } } // make query to subdirectory DocumentModelList l = dirInfo.getSession().query(dirFilter, dirFulltext, null, fetchReferences); for (DocumentModel entry : l) { final String id = entry.getId(); Map<String, Object> map = maps.get(id); if (map == null) { map = new HashMap<String, Object>(); maps.put(id, map); counts.put(id, 1); } else { counts.put(id, counts.get(id) + 1); } for (Entry<String, String> e : dirInfo.toSource.entrySet()) { map.put(e.getValue(), entry.getProperty(dirInfo.dirSchemaName, e.getKey())); } if (BaseSession.isReadOnlyEntry(entry)) { readOnlyEntries.add(id); } } } // add default entry values for optional dirs for (SubDirectoryInfo dirInfo : optionalDirsMatching) { // add entry for every data found in other dirs Set<String> existingIds = new HashSet<String>( dirInfo .getSession() .getProjection(Collections.<String, Serializable>emptyMap(), dirInfo.idField)); for (Entry<String, Map<String, Object>> result : maps.entrySet()) { final String id = result.getKey(); if (!existingIds.contains(id)) { counts.put(id, counts.get(id) + 1); final Map<String, Object> map = result.getValue(); for (Entry<String, String> e : dirInfo.toSource.entrySet()) { String value = e.getValue(); if (!map.containsKey(value)) { map.put(value, dirInfo.defaultEntry.get(e.getKey())); } } } } } // intersection, ignore entries not in all subdirectories final int numdirs = sourceInfo.subDirectoryInfos.size(); for (Iterator<String> it = maps.keySet().iterator(); it.hasNext(); ) { final String id = it.next(); if (counts.get(id) != numdirs) { it.remove(); } } // now create entries ((ArrayList<?>) results).ensureCapacity(results.size() + maps.size()); for (Entry<String, Map<String, Object>> e : maps.entrySet()) { final String id = e.getKey(); if (seen.containsKey(id)) { log.warn( String.format( "Entry '%s' is present in source '%s' but also in source '%s'. " + "The second one will be ignored.", id, seen.get(id), sourceInfo.source.name)); continue; } final Map<String, Object> map = e.getValue(); seen.put(id, sourceInfo.source.name); final DocumentModel entry = BaseSession.createEntryModel(null, schemaName, id, map, readOnlyEntries.contains(id)); results.add(entry); } } if (orderBy != null && !orderBy.isEmpty()) { directory.orderEntries(results, orderBy); } return results; }
@Override @SuppressWarnings("boxing") public DocumentModelList getEntries() { if (!isCurrentUserAllowed(SecurityConstants.READ)) { return null; } init(); // list of entries final DocumentModelList results = new DocumentModelListImpl(); // entry ids already seen (mapped to the source name) final Map<String, String> seen = new HashMap<String, String>(); Set<String> readOnlyEntries = new HashSet<String>(); for (SourceInfo sourceInfo : sourceInfos) { // accumulated map for each entry final Map<String, Map<String, Object>> maps = new HashMap<String, Map<String, Object>>(); // number of dirs seen for each entry final Map<String, Integer> counts = new HashMap<String, Integer>(); for (SubDirectoryInfo dirInfo : sourceInfo.requiredSubDirectoryInfos) { final DocumentModelList entries = dirInfo.getSession().getEntries(); for (DocumentModel entry : entries) { final String id = entry.getId(); // find or create map for this entry Map<String, Object> map = maps.get(id); if (map == null) { map = new HashMap<String, Object>(); maps.put(id, map); counts.put(id, 1); } else { counts.put(id, counts.get(id) + 1); } // put entry data in map for (Entry<String, String> e : dirInfo.toSource.entrySet()) { map.put(e.getValue(), entry.getProperty(dirInfo.dirSchemaName, e.getKey())); } if (BaseSession.isReadOnlyEntry(entry)) { readOnlyEntries.add(id); } } } for (SubDirectoryInfo dirInfo : sourceInfo.optionalSubDirectoryInfos) { final DocumentModelList entries = dirInfo.getSession().getEntries(); Set<String> existingIds = new HashSet<String>(); for (DocumentModel entry : entries) { final String id = entry.getId(); final Map<String, Object> map = maps.get(id); if (map != null) { existingIds.add(id); // put entry data in map for (Entry<String, String> e : dirInfo.toSource.entrySet()) { map.put(e.getValue(), entry.getProperty(dirInfo.dirSchemaName, e.getKey())); } } else { log.warn( String.format( "Entry '%s' for source '%s' is present in optional directory '%s' " + "but not in any required one. " + "It will be skipped.", id, sourceInfo.source.name, dirInfo.dirName)); } } for (Entry<String, Map<String, Object>> mapEntry : maps.entrySet()) { if (!existingIds.contains(mapEntry.getKey())) { final Map<String, Object> map = mapEntry.getValue(); // put entry data in map for (Entry<String, String> e : dirInfo.toSource.entrySet()) { // fill with default values for this directory if (!map.containsKey(e.getValue())) { map.put(e.getValue(), dirInfo.defaultEntry.get(e.getKey())); } } } } } // now create entries for all full maps int numdirs = sourceInfo.requiredSubDirectoryInfos.size(); ((ArrayList<?>) results).ensureCapacity(results.size() + maps.size()); for (Entry<String, Map<String, Object>> e : maps.entrySet()) { final String id = e.getKey(); if (seen.containsKey(id)) { log.warn( String.format( "Entry '%s' is present in source '%s' but also in source '%s'. " + "The second one will be ignored.", id, seen.get(id), sourceInfo.source.name)); continue; } final Map<String, Object> map = e.getValue(); if (counts.get(id) != numdirs) { log.warn( String.format( "Entry '%s' for source '%s' is not present in all directories. " + "It will be skipped.", id, sourceInfo.source.name)); continue; } seen.put(id, sourceInfo.source.name); final DocumentModel entry = BaseSession.createEntryModel(null, schemaName, id, map, readOnlyEntries.contains(id)); results.add(entry); } } return results; }
@Test public void testReadOnlyEntryInGetEntriesResults() throws Exception { Map<String, String> orderBy = new HashMap<String, String>(); orderBy.put("schema3:uid", "asc"); DocumentModelComparator comp = new DocumentModelComparator(orderBy); DocumentModelList results = dir.getEntries(); Collections.sort(results, comp); // by default no backing dir is readonly assertFalse(BaseSession.isReadOnlyEntry(results.get(0))); assertFalse(BaseSession.isReadOnlyEntry(results.get(1))); assertFalse(BaseSession.isReadOnlyEntry(results.get(2))); assertFalse(BaseSession.isReadOnlyEntry(results.get(3))); memdir1.setReadOnly(true); memdir2.setReadOnly(false); memdir3.setReadOnly(false); results = dir.getEntries(); Collections.sort(results, comp); assertTrue(BaseSession.isReadOnlyEntry(results.get(0))); assertTrue(BaseSession.isReadOnlyEntry(results.get(1))); assertFalse(BaseSession.isReadOnlyEntry(results.get(2))); assertFalse(BaseSession.isReadOnlyEntry(results.get(3))); memdir1.setReadOnly(false); memdir2.setReadOnly(false); memdir3.setReadOnly(true); results = dir.getEntries(); Collections.sort(results, comp); assertFalse(BaseSession.isReadOnlyEntry(results.get(0))); assertFalse(BaseSession.isReadOnlyEntry(results.get(1))); assertTrue(BaseSession.isReadOnlyEntry(results.get(2))); assertTrue(BaseSession.isReadOnlyEntry(results.get(3))); }
@Test public void testReadOnlyEntryFromGetEntry() throws Exception { // by default no backing dir is readonly assertFalse(BaseSession.isReadOnlyEntry(dir.getEntry("1"))); assertFalse(BaseSession.isReadOnlyEntry(dir.getEntry("2"))); assertFalse(BaseSession.isReadOnlyEntry(dir.getEntry("3"))); assertFalse(BaseSession.isReadOnlyEntry(dir.getEntry("4"))); memdir1.setReadOnly(true); memdir2.setReadOnly(false); memdir3.setReadOnly(false); assertFalse(BaseSession.isReadOnlyEntry(dir.getEntry("1"))); assertFalse(BaseSession.isReadOnlyEntry(dir.getEntry("2"))); assertFalse(BaseSession.isReadOnlyEntry(dir.getEntry("3"))); assertFalse(BaseSession.isReadOnlyEntry(dir.getEntry("4"))); memdir1.setReadOnly(false); memdir2.setReadOnly(true); memdir3.setReadOnly(true); assertFalse(BaseSession.isReadOnlyEntry(dir.getEntry("1"))); assertFalse(BaseSession.isReadOnlyEntry(dir.getEntry("2"))); assertTrue(BaseSession.isReadOnlyEntry(dir.getEntry("3"))); assertTrue(BaseSession.isReadOnlyEntry(dir.getEntry("4"))); memdir1.setReadOnly(false); memdir2.setReadOnly(false); memdir3.setReadOnly(true); assertFalse(BaseSession.isReadOnlyEntry(dir.getEntry("1"))); assertFalse(BaseSession.isReadOnlyEntry(dir.getEntry("2"))); assertTrue(BaseSession.isReadOnlyEntry(dir.getEntry("3"))); assertTrue(BaseSession.isReadOnlyEntry(dir.getEntry("4"))); memdir1.setReadOnly(true); memdir2.setReadOnly(true); memdir3.setReadOnly(false); assertTrue(BaseSession.isReadOnlyEntry(dir.getEntry("1"))); assertTrue(BaseSession.isReadOnlyEntry(dir.getEntry("2"))); assertFalse(BaseSession.isReadOnlyEntry(dir.getEntry("3"))); assertFalse(BaseSession.isReadOnlyEntry(dir.getEntry("4"))); }