From 5786da5350aeff78cad35ec6f57319aca26e79fa Mon Sep 17 00:00:00 2001 From: Oscar Arrieta Date: Thu, 1 Jun 2017 17:15:04 -0600 Subject: [PATCH] #11793: Adding case when field has same var but diff id (#11806) * #11793: Adding case when field has same var but diff id * #11793 removing ContentTypeCache calls from FieldFactory * #11793 killing cache flushes --- .../test/ContentTypeAPIImplTest.java | 343 +++++++++++------- .../business/ESContentletAPIImpl.java | 2 +- .../contenttype/business/ContentTypeAPI.java | 5 +- .../business/ContentTypeAPIImpl.java | 305 ++++++++-------- .../business/ContentTypeFactoryImpl.java | 6 +- .../business/FieldFactoryImpl.java | 61 +--- 6 files changed, 382 insertions(+), 340 deletions(-) diff --git a/dotCMS/src/integration-test/java/com/dotcms/contenttype/test/ContentTypeAPIImplTest.java b/dotCMS/src/integration-test/java/com/dotcms/contenttype/test/ContentTypeAPIImplTest.java index 4dbf6062b01d..71f20ee89184 100644 --- a/dotCMS/src/integration-test/java/com/dotcms/contenttype/test/ContentTypeAPIImplTest.java +++ b/dotCMS/src/integration-test/java/com/dotcms/contenttype/test/ContentTypeAPIImplTest.java @@ -1,44 +1,25 @@ package com.dotcms.contenttype.test; -import static org.hamcrest.MatcherAssert.assertThat; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.Date; -import java.util.List; -import java.util.UUID; - -import org.junit.Test; - import com.dotcms.contenttype.business.FieldFactoryImpl; import com.dotcms.contenttype.exception.NotFoundInDbException; -import com.dotcms.contenttype.model.field.DataTypes; -import com.dotcms.contenttype.model.field.Field; -import com.dotcms.contenttype.model.field.FieldBuilder; -import com.dotcms.contenttype.model.field.FieldVariable; -import com.dotcms.contenttype.model.field.ImmutableFieldVariable; -import com.dotcms.contenttype.model.field.OnePerContentType; -import com.dotcms.contenttype.model.field.WysiwygField; -import com.dotcms.contenttype.model.type.BaseContentType; -import com.dotcms.contenttype.model.type.ContentType; -import com.dotcms.contenttype.model.type.ContentTypeBuilder; -import com.dotcms.contenttype.model.type.Expireable; -import com.dotcms.contenttype.model.type.ImmutableFileAssetContentType; -import com.dotcms.contenttype.model.type.ImmutableFormContentType; -import com.dotcms.contenttype.model.type.ImmutablePageContentType; -import com.dotcms.contenttype.model.type.ImmutablePersonaContentType; -import com.dotcms.contenttype.model.type.ImmutableSimpleContentType; -import com.dotcms.contenttype.model.type.ImmutableWidgetContentType; -import com.dotcms.contenttype.model.type.UrlMapable; +import com.dotcms.contenttype.model.field.*; +import com.dotcms.contenttype.model.type.*; import com.dotcms.repackage.org.apache.commons.lang.StringUtils; import com.dotmarketing.beans.Host; import com.dotmarketing.business.APILocator; import com.dotmarketing.exception.DotDataException; import com.dotmarketing.exception.DotSecurityException; import com.dotmarketing.portlets.folders.business.FolderAPI; +import org.junit.Assert; +import org.junit.Test; + +import java.io.*; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import static org.hamcrest.MatcherAssert.assertThat; public class ContentTypeAPIImplTest extends ContentTypeBaseTest { @@ -557,115 +538,203 @@ public void testAddingUpdatingDeletingContentTypeWithFixedFields() throws Except //deleting content type delete(type); } - + + /** + * Test the updateModDate method of the contenttypeapi + * to help detect the changes on fields and field variables + * @throws Exception + */ + @Test + public void testUpdateContentTypeModDate() throws Exception{ + long time = System.currentTimeMillis(); + String TEST_VAR_PREFIX = "myTestField"; + String TEST_FIELD_VAR_PREFIX = "myTestFieldVar"; + String TEST_FIELD_VAR_VALUE_PREFIX = "myTestFieldVar"; + int base = BaseContentType.CONTENT.ordinal(); + + Thread.sleep(1); + ContentType type = ContentTypeBuilder.builder(BaseContentType.getContentTypeClass(base)) + .description("description" + time).folder(FolderAPI.SYSTEM_FOLDER).host(Host.SYSTEM_HOST) + .name("ContentTypeTestingUpdateModDate" + time).owner("owner").variable("velocityVarNameTesting" + time).build(); + type = contentTypeApi.save(type, null, null); + + int fieldsCount = type.fields().size(); + Date creationModDate = type.modDate(); + assertThat("contenttypes mod_date is not null", creationModDate != null); + //calling updatemod_date method + Thread.sleep(1000); + contentTypeApi.updateModDate(type); + //getting new mod_date + type = contentTypeApi.find(type.id()); + Date currentModDate = type.modDate(); + assertThat("contenttypes current mod_date is not null", currentModDate != null); + assertThat("contenttypes mod_date is updated", creationModDate != currentModDate); + assertThat("contenttypes mod_date is updated", currentModDate.compareTo(creationModDate) > 0); + + //Test Content Type mod_date changes after adding a Field + Thread.sleep(1000); + Field savedField = FieldBuilder.builder(WysiwygField.class).name("my test field") + .variable(TEST_VAR_PREFIX + "textField").contentTypeId(type.id()).dataType(DataTypes.LONG_TEXT).build(); + savedField = APILocator.getContentTypeFieldAPI().save(savedField, APILocator.systemUser()); + type = contentTypeApi.find(type.id()); + int updatedFieldsCount = type.fields().size(); + Date addFieldDate = type.modDate(); + assertThat("contenttypes current mod_date is not null", addFieldDate != null); + assertThat("contenttypes mod_date is updated", addFieldDate != currentModDate); + assertThat("contenttypes mod_date is updated after add Field", addFieldDate.compareTo(currentModDate) > 0); + assertThat("contenttypes fields incremented", updatedFieldsCount > fieldsCount); + + //Test Content Type mod_date changes after edit Field + Thread.sleep(1000); + savedField = FieldBuilder.builder(savedField).indexed(true).build(); + savedField = APILocator.getContentTypeFieldAPI().save(savedField, APILocator.systemUser()); + type = contentTypeApi.find(type.id()); + Date editFieldDate = type.modDate(); + int updatedFieldsCount2 = type.fields().size(); + assertThat("contenttypes current mod_date is not null", editFieldDate != null); + assertThat("contenttypes mod_date is updated", editFieldDate != addFieldDate); + assertThat("contenttypes mod_date is updated after edit Field", editFieldDate.compareTo(addFieldDate) > 0); + assertThat("contenttypes fields are the same", updatedFieldsCount == updatedFieldsCount2); + + //Test Content Type mod_date changes after adding a Field Variable + Thread.sleep(1000); + FieldVariable savedFieldVar = ImmutableFieldVariable.builder().id(null) + .fieldId(savedField.id()).name(TEST_FIELD_VAR_PREFIX+time) + .key(TEST_FIELD_VAR_PREFIX+time).value(TEST_FIELD_VAR_VALUE_PREFIX+time) + .userId(APILocator.systemUser().getUserId()).modDate(new Date()).build(); + savedFieldVar = APILocator.getContentTypeFieldAPI().save(savedFieldVar, APILocator.systemUser()); + type = contentTypeApi.find(type.id()); + Date addFieldVariableDate = type.modDate(); + assertThat("contenttypes current mod_date is not null", addFieldVariableDate != null); + assertThat("contenttypes mod_date is updated", addFieldVariableDate != editFieldDate); + assertThat("contenttypes mod_date is updated after add Field Variable", addFieldVariableDate.compareTo(editFieldDate) > 0); + assertThat("Field Variable is added ",APILocator.getContentTypeFieldAPI().find(savedField.id()).fieldVariables().size() == 1); + + //Test Content Type mod_date changes after editing a Field Variable + Thread.sleep(1000); + savedFieldVar = ImmutableFieldVariable.builder().id(savedFieldVar.id()) + .fieldId(savedField.id()).name(TEST_FIELD_VAR_PREFIX+time) + .key(TEST_FIELD_VAR_PREFIX+time).value(TEST_FIELD_VAR_VALUE_PREFIX+(time+1)) + .userId(APILocator.systemUser().getUserId()).modDate(new Date()).build(); + savedFieldVar = APILocator.getContentTypeFieldAPI().save(savedFieldVar, APILocator.systemUser()); + type = contentTypeApi.find(type.id()); + Date editFieldVariableDate = type.modDate(); + assertThat("contenttypes current mod_date is not null", editFieldVariableDate != null); + assertThat("contenttypes mod_date is updated", editFieldVariableDate != addFieldVariableDate); + assertThat("contenttypes mod_date is updated", editFieldVariableDate.compareTo(addFieldVariableDate) > 0); + assertThat("Field Variable is updated ",APILocator.getContentTypeFieldAPI().find(savedField.id()).fieldVariables().size() == 1); + assertThat("Field Variable was updated properly",APILocator.getContentTypeFieldAPI().find(savedField.id()).fieldVariables().get(0).value().equals(TEST_FIELD_VAR_VALUE_PREFIX+(time+1))); + + //Test Content Type mod_date changes after deleting a Field Variable + Thread.sleep(1000); + APILocator.getContentTypeFieldAPI().delete(savedFieldVar); + type = contentTypeApi.find(type.id()); + Date deleteFieldVarDate = type.modDate(); + updatedFieldsCount = type.fields().size(); + assertThat("contenttypes current mod_date is not null", deleteFieldVarDate != null); + assertThat("contenttypes mod_date is updated", deleteFieldVarDate != editFieldVariableDate); + assertThat("contenttypes mod_date is updated after delete Field Variable", deleteFieldVarDate.compareTo(editFieldVariableDate) > 0); + assertThat("Field Variable is removed ",APILocator.getContentTypeFieldAPI().find(savedField.id()).fieldVariables().size() == 0); + + //Test Content Type mod_date changes after deleting a Field + Thread.sleep(1000); + APILocator.getContentTypeFieldAPI().delete(savedField); + type = contentTypeApi.find(type.id()); + Date deleteFieldDate = type.modDate(); + updatedFieldsCount = type.fields().size(); + assertThat("contenttypes current mod_date is not null", deleteFieldDate != null); + assertThat("contenttypes mod_date is updated", deleteFieldDate != deleteFieldVarDate); + assertThat("contenttypes mod_date is updated after delete Field", deleteFieldDate.compareTo(deleteFieldVarDate) > 0); + assertThat("contenttypes field removed", updatedFieldsCount == fieldsCount); + //deleting content type + delete(type); + } + /** - * Test the updateModDate method of the contenttypeapi - * to help detect the changes on fields and field variables + * Creates a Content Type with a fixed field and then tries to update it with a field with same VarName and DBColumn but different ID. * @throws Exception */ @Test - public void testUpdateContentTypeModDate() throws Exception{ - long time = System.currentTimeMillis(); - String TEST_VAR_PREFIX = "myTestField"; - String TEST_FIELD_VAR_PREFIX = "myTestFieldVar"; - String TEST_FIELD_VAR_VALUE_PREFIX = "myTestFieldVar"; - int base = BaseContentType.CONTENT.ordinal(); - - Thread.sleep(1); - ContentType type = ContentTypeBuilder.builder(BaseContentType.getContentTypeClass(base)) - .description("description" + time).folder(FolderAPI.SYSTEM_FOLDER).host(Host.SYSTEM_HOST) - .name("ContentTypeTestingUpdateModDate" + time).owner("owner").variable("velocityVarNameTesting" + time).build(); - type = contentTypeApi.save(type, null, null); - - int fieldsCount = type.fields().size(); - Date creationModDate = type.modDate(); - assertThat("contenttypes mod_date is not null", creationModDate != null); - //calling updatemod_date method - Thread.sleep(1000); - contentTypeApi.updateModDate(type); - //getting new mod_date - type = contentTypeApi.find(type.id()); - Date currentModDate = type.modDate(); - assertThat("contenttypes current mod_date is not null", currentModDate != null); - assertThat("contenttypes mod_date is updated", creationModDate != currentModDate); - assertThat("contenttypes mod_date is updated", currentModDate.compareTo(creationModDate) > 0); - - //Test Content Type mod_date changes after adding a Field - Thread.sleep(1000); - Field savedField = FieldBuilder.builder(WysiwygField.class).name("my test field") - .variable(TEST_VAR_PREFIX + "textField").contentTypeId(type.id()).dataType(DataTypes.LONG_TEXT).build(); - savedField = APILocator.getContentTypeFieldAPI().save(savedField, APILocator.systemUser()); - type = contentTypeApi.find(type.id()); - int updatedFieldsCount = type.fields().size(); - Date addFieldDate = type.modDate(); - assertThat("contenttypes current mod_date is not null", addFieldDate != null); - assertThat("contenttypes mod_date is updated", addFieldDate != currentModDate); - assertThat("contenttypes mod_date is updated after add Field", addFieldDate.compareTo(currentModDate) > 0); - assertThat("contenttypes fields incremented", updatedFieldsCount > fieldsCount); - - //Test Content Type mod_date changes after edit Field - Thread.sleep(1000); - savedField = FieldBuilder.builder(savedField).indexed(true).build(); - savedField = APILocator.getContentTypeFieldAPI().save(savedField, APILocator.systemUser()); - type = contentTypeApi.find(type.id()); - Date editFieldDate = type.modDate(); - int updatedFieldsCount2 = type.fields().size(); - assertThat("contenttypes current mod_date is not null", editFieldDate != null); - assertThat("contenttypes mod_date is updated", editFieldDate != addFieldDate); - assertThat("contenttypes mod_date is updated after edit Field", editFieldDate.compareTo(addFieldDate) > 0); - assertThat("contenttypes fields are the same", updatedFieldsCount == updatedFieldsCount2); - - //Test Content Type mod_date changes after adding a Field Variable - Thread.sleep(1000); - FieldVariable savedFieldVar = ImmutableFieldVariable.builder().id(null) - .fieldId(savedField.id()).name(TEST_FIELD_VAR_PREFIX+time) - .key(TEST_FIELD_VAR_PREFIX+time).value(TEST_FIELD_VAR_VALUE_PREFIX+time) - .userId(APILocator.systemUser().getUserId()).modDate(new Date()).build(); - savedFieldVar = APILocator.getContentTypeFieldAPI().save(savedFieldVar, APILocator.systemUser()); - type = contentTypeApi.find(type.id()); - Date addFieldVariableDate = type.modDate(); - assertThat("contenttypes current mod_date is not null", addFieldVariableDate != null); - assertThat("contenttypes mod_date is updated", addFieldVariableDate != editFieldDate); - assertThat("contenttypes mod_date is updated after add Field Variable", addFieldVariableDate.compareTo(editFieldDate) > 0); - assertThat("Field Variable is added ",APILocator.getContentTypeFieldAPI().find(savedField.id()).fieldVariables().size() == 1); - - //Test Content Type mod_date changes after editing a Field Variable - Thread.sleep(1000); - savedFieldVar = ImmutableFieldVariable.builder().id(savedFieldVar.id()) - .fieldId(savedField.id()).name(TEST_FIELD_VAR_PREFIX+time) - .key(TEST_FIELD_VAR_PREFIX+time).value(TEST_FIELD_VAR_VALUE_PREFIX+(time+1)) - .userId(APILocator.systemUser().getUserId()).modDate(new Date()).build(); - savedFieldVar = APILocator.getContentTypeFieldAPI().save(savedFieldVar, APILocator.systemUser()); - type = contentTypeApi.find(type.id()); - Date editFieldVariableDate = type.modDate(); - assertThat("contenttypes current mod_date is not null", editFieldVariableDate != null); - assertThat("contenttypes mod_date is updated", editFieldVariableDate != addFieldVariableDate); - assertThat("contenttypes mod_date is updated", editFieldVariableDate.compareTo(addFieldVariableDate) > 0); - assertThat("Field Variable is updated ",APILocator.getContentTypeFieldAPI().find(savedField.id()).fieldVariables().size() == 1); - assertThat("Field Variable was updated properly",APILocator.getContentTypeFieldAPI().find(savedField.id()).fieldVariables().get(0).value().equals(TEST_FIELD_VAR_VALUE_PREFIX+(time+1))); - - //Test Content Type mod_date changes after deleting a Field Variable - Thread.sleep(1000); - APILocator.getContentTypeFieldAPI().delete(savedFieldVar); - type = contentTypeApi.find(type.id()); - Date deleteFieldVarDate = type.modDate(); - updatedFieldsCount = type.fields().size(); - assertThat("contenttypes current mod_date is not null", deleteFieldVarDate != null); - assertThat("contenttypes mod_date is updated", deleteFieldVarDate != editFieldVariableDate); - assertThat("contenttypes mod_date is updated after delete Field Variable", deleteFieldVarDate.compareTo(editFieldVariableDate) > 0); - assertThat("Field Variable is removed ",APILocator.getContentTypeFieldAPI().find(savedField.id()).fieldVariables().size() == 0); - - //Test Content Type mod_date changes after deleting a Field - Thread.sleep(1000); - APILocator.getContentTypeFieldAPI().delete(savedField); - type = contentTypeApi.find(type.id()); - Date deleteFieldDate = type.modDate(); - updatedFieldsCount = type.fields().size(); - assertThat("contenttypes current mod_date is not null", deleteFieldDate != null); - assertThat("contenttypes mod_date is updated", deleteFieldDate != deleteFieldVarDate); - assertThat("contenttypes mod_date is updated after delete Field", deleteFieldDate.compareTo(deleteFieldVarDate) > 0); - assertThat("contenttypes field removed", updatedFieldsCount == fieldsCount); - //deleting content type - delete(type); + public void testUpdatingContentTypeWithFixedFieldsDifferentFieldID() throws Exception{ + + int base = BaseContentType.WIDGET.ordinal(); + long time = System.currentTimeMillis(); + + final String FIRST_UUID = UUID.randomUUID().toString(); + final String FIRST_NAME = "My Fixed Field"; + final String SECOND_UUID = UUID.randomUUID().toString(); + final String SECOND_NAME = "My Fixed Field Updated"; + + ContentType contentType = ContentTypeBuilder + .builder(BaseContentType.getContentTypeClass(base)) + .description("Description" + time) + .folder(FolderAPI.SYSTEM_FOLDER) + .host(Host.SYSTEM_HOST) + .name("ContentTypeWithFixedFieldsDifferentFieldID" + time) + .owner("Me") + .variable("CTVariable" + time) + .build(); + contentType = contentTypeApi.save(contentType); + + assertThat("ContentType exists", contentTypeApi.find( contentType.inode() ) != null); + + //Add Field. + List fields = new ArrayList<>( contentType.fields() ); + List originalFields = new ArrayList<>( fields ); + + int originalFieldSize = fields.size(); + + final String TEST_VAR_NAME = "myFixedVarName"; + + Field fieldToSave = FieldBuilder.builder( TextField.class ) + .name( FIRST_NAME ) + .variable( TEST_VAR_NAME ) + .contentTypeId( contentType.id() ) + .dataType( DataTypes.TEXT ) + .fixed( true ) + .dbColumn( "text15" ) + .id( FIRST_UUID ) + .build(); + + fields.add( fieldToSave ); + + contentType = contentTypeApi.save( contentType, fields ); + + //Lets check that the Field was added. + Field fieldFound = null; + for ( Field field : contentType.fields() ) { + if ( field.id().equals( FIRST_UUID ) ){ + fieldFound = field; + } + } + Assert.assertNotNull( fieldFound ); + Assert.assertEquals( FIRST_NAME, fieldFound.name() ); + + Field fieldToSaveDifferentID = FieldBuilder.builder( TextField.class ) + .name( SECOND_NAME ) + .variable( TEST_VAR_NAME ) + .contentTypeId( contentType.id() ) + .dataType( DataTypes.TEXT ) + .fixed( true ) + .dbColumn( "text15" ) + .id( SECOND_UUID ) + .build(); + + originalFields.add( fieldToSaveDifferentID ); + + contentType = contentTypeApi.save( contentType, originalFields ); + + //Lets check that the Field was updated. + fieldFound = null; + for ( Field field : contentType.fields() ) { + if ( field.id().equals( FIRST_UUID ) ){ + fieldFound = field; + } + } + Assert.assertNotNull( fieldFound ); + Assert.assertEquals( SECOND_NAME, fieldFound.name() ); + + //Deleting content type. + delete(contentType); } } diff --git a/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentletAPIImpl.java b/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentletAPIImpl.java index 80920ee3448f..e79657aa3ae2 100644 --- a/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentletAPIImpl.java +++ b/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentletAPIImpl.java @@ -1935,7 +1935,7 @@ public void reindex(Contentlet contentlet)throws DotReindexStateException, DotDa public void refresh(Structure structure) throws DotReindexStateException { try { distAPI.addStructureReindexEntries(structure.getInode()); - CacheLocator.getContentletCache().clearCache(); + //CacheLocator.getContentletCache().clearCache(); } catch (DotDataException e) { Logger.error(this, e.getMessage(), e); throw new DotReindexStateException("Unable to complete reindex",e); diff --git a/dotCMS/src/main/java/com/dotcms/contenttype/business/ContentTypeAPI.java b/dotCMS/src/main/java/com/dotcms/contenttype/business/ContentTypeAPI.java index 75f0a8d6f289..78e3e2d76b6f 100644 --- a/dotCMS/src/main/java/com/dotcms/contenttype/business/ContentTypeAPI.java +++ b/dotCMS/src/main/java/com/dotcms/contenttype/business/ContentTypeAPI.java @@ -284,7 +284,10 @@ List search(String condition, BaseContentType base, String orderBy, * Update the Content Type mod_date and clean the cache * @param type Content Type that is going to be modified * @return true if the mod_date was updated, false if not + * @throws DotDataException */ - boolean updateModDate(ContentType type); + boolean updateModDate(ContentType type) throws DotDataException; + + boolean updateModDate(Field field) throws DotDataException; } diff --git a/dotCMS/src/main/java/com/dotcms/contenttype/business/ContentTypeAPIImpl.java b/dotCMS/src/main/java/com/dotcms/contenttype/business/ContentTypeAPIImpl.java index 68c3d6ea2b46..e8e731b8771d 100644 --- a/dotCMS/src/main/java/com/dotcms/contenttype/business/ContentTypeAPIImpl.java +++ b/dotCMS/src/main/java/com/dotcms/contenttype/business/ContentTypeAPIImpl.java @@ -1,8 +1,5 @@ package com.dotcms.contenttype.business; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; - import com.dotcms.api.system.event.ContentTypePayloadDataWrapper; import com.dotcms.api.system.event.Payload; import com.dotcms.api.system.event.SystemEventType; @@ -10,6 +7,7 @@ import com.dotcms.contenttype.business.sql.ContentTypeSql; import com.dotcms.contenttype.exception.NotFoundInDbException; import com.dotcms.contenttype.model.field.Field; +import com.dotcms.contenttype.model.field.FieldBuilder; import com.dotcms.contenttype.model.field.FieldVariable; import com.dotcms.contenttype.model.type.BaseContentType; import com.dotcms.contenttype.model.type.ContentType; @@ -20,39 +18,24 @@ import com.dotcms.util.ContentTypeUtil; import com.dotmarketing.beans.Host; import com.dotmarketing.beans.PermissionableProxy; -import com.dotmarketing.business.APILocator; -import com.dotmarketing.business.CacheLocator; -import com.dotmarketing.business.DotStateException; -import com.dotmarketing.business.FactoryLocator; -import com.dotmarketing.business.PermissionAPI; -import com.dotmarketing.business.PermissionLevel; -import com.dotmarketing.business.Permissionable; +import com.dotmarketing.business.*; import com.dotmarketing.common.db.DotConnect; import com.dotmarketing.db.LocalTransaction; import com.dotmarketing.exception.DotDataException; +import com.dotmarketing.exception.DotRuntimeException; import com.dotmarketing.exception.DotSecurityException; import com.dotmarketing.portlets.contentlet.business.HostAPI; import com.dotmarketing.portlets.contentlet.model.Contentlet; import com.dotmarketing.portlets.folders.model.Folder; import com.dotmarketing.portlets.structure.model.SimpleStructureURLMap; import com.dotmarketing.quartz.job.IdentifierDateJob; -import com.dotmarketing.util.ActivityLogger; -import com.dotmarketing.util.AdminLogger; -import com.dotmarketing.util.Logger; -import com.dotmarketing.util.UUIDUtil; -import com.dotmarketing.util.UtilMethods; +import com.dotmarketing.util.*; import com.dotmarketing.util.json.JSONArray; import com.dotmarketing.util.json.JSONObject; import com.liferay.portal.model.User; - import org.elasticsearch.action.search.SearchResponse; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; +import java.util.*; public class ContentTypeAPIImpl implements ContentTypeAPI { @@ -66,7 +49,7 @@ public class ContentTypeAPIImpl implements ContentTypeAPI { public ContentTypeAPIImpl(User user, boolean respectFrontendRoles, ContentTypeFactory fac, FieldFactory ffac, - PermissionAPI perms, FieldAPI fAPI) { + PermissionAPI perms, FieldAPI fAPI) { super(); this.fac = fac; this.ffac = ffac; @@ -190,8 +173,8 @@ public int count(String condition) throws DotDataException { @Override public int count(String condition, BaseContentType base) throws DotDataException { try { - return perms.filterCollection(this.fac.search(condition, base, "mod_date", -1, 0), - PermissionAPI.PERMISSION_READ, true, user).size(); + return perms.filterCollection(this.fac.search(condition, base, "mod_date", -1, 0), PermissionAPI.PERMISSION_READ, + true, user).size(); } catch (DotSecurityException e) { throw new DotStateException(e); } @@ -199,13 +182,9 @@ public int count(String condition, BaseContentType base) throws DotDataException - - - - @Override public ContentType save(ContentType type) throws DotDataException, DotSecurityException { - return save(type, null, null); + return save(type, null, null); } @Override @@ -255,20 +234,20 @@ public List findByType(BaseContentType type) throws DotDataExceptio } } - @Override - public List findStructureURLMapPatterns() throws DotDataException { - List res = new ArrayList<>(); - - for ( ContentType type : fac.findUrlMapped() ){ - if (type instanceof UrlMapable){ - res.add(new SimpleStructureURLMap(type.id(), type.urlMapPattern())); - } + @Override + public List findStructureURLMapPatterns() throws DotDataException { + List res = new ArrayList<>(); - } + for (ContentType type : fac.findUrlMapped()) { + if (type instanceof UrlMapable) { + res.add(new SimpleStructureURLMap(type.id(), type.urlMapPattern())); + } - return ImmutableList.copyOf(res); } + return ImmutableList.copyOf(res); + } + @Override public void moveToSystemFolder(Folder folder) throws DotDataException { @@ -339,14 +318,8 @@ public List recentlyUsed(BaseContentType type, int numberToShow) th } public Map getEntriesByContentTypes() throws DotDataException { - String query = "{" + - " \"aggs\" : {" + - " \"entries\" : {" + - " \"terms\" : { \"field\" : \"contenttype\" }" + - " }" + - " }," + - " size:0" + - "}"; + String query = "{" + " \"aggs\" : {" + " \"entries\" : {" + " \"terms\" : { \"field\" : \"contenttype\" }" + + " }" + " }," + " size:0" + "}"; try { SearchResponse raw = APILocator.getEsSearchAPI().esSearchRaw(query.toLowerCase(), false, user, false); @@ -399,132 +372,160 @@ public List search(String condition, BaseContentType base, String o public List findUrlMapped() throws DotDataException { return fac.findUrlMapped(); } - + @Override - public ContentType save(ContentType contentType, List newFields) throws DotDataException, DotSecurityException { - return save(contentType, newFields, null); + public ContentType save(ContentType contentType, List newFields) + throws DotDataException, DotSecurityException { + return save(contentType, newFields, null); } @Override - public ContentType save(ContentType contentType, List newFields, List newFieldVariables) throws DotDataException, DotSecurityException { - // Sets the host: - try { - if ( contentType.host() == null ) { - contentType = ContentTypeBuilder.builder( contentType ).host( Host.SYSTEM_HOST ).build(); - } - if ( !UUIDUtil.isUUID( contentType.host() ) && !Host.SYSTEM_HOST.equalsIgnoreCase( contentType.host() ) ) { - HostAPI hapi = APILocator.getHostAPI(); - contentType = ContentTypeBuilder.builder( contentType ) - .host( hapi.resolveHostName( contentType.host(), APILocator.systemUser(), true ).getIdentifier() ) - .build(); - } - } catch ( DotDataException e ) { - throw new DotDataException( "unable to resolve host:" + contentType.host(), e ); - } catch ( DotSecurityException es ) { - throw new DotSecurityException( "invalid permissions to:" + contentType.host(), es ); + public ContentType save(ContentType contentType, List newFields, List newFieldVariables) + throws DotDataException, DotSecurityException { + // Sets the host: + try { + if (contentType.host() == null) { + contentType = ContentTypeBuilder.builder(contentType).host(Host.SYSTEM_HOST).build(); + } + if (!UUIDUtil.isUUID(contentType.host()) && !Host.SYSTEM_HOST.equalsIgnoreCase(contentType.host())) { + HostAPI hapi = APILocator.getHostAPI(); + contentType = ContentTypeBuilder.builder(contentType) + .host(hapi.resolveHostName(contentType.host(), APILocator.systemUser(), true).getIdentifier()).build(); + } + } catch (DotDataException e) { + throw new DotDataException("unable to resolve host:" + contentType.host(), e); + } catch (DotSecurityException es) { + throw new DotSecurityException("invalid permissions to:" + contentType.host(), es); + } + + // check perms + Permissionable parent = contentType.getParentPermissionable(); + if (!perms.doesUserHavePermissions(parent, + "PARENT:" + PermissionAPI.PERMISSION_CAN_ADD_CHILDREN + ", STRUCTURES:" + PermissionAPI.PERMISSION_PUBLISH, + user)) { + throw new DotSecurityException( + "User-does-not-have-add-children-or-structure-permission-on-host-folder:" + parent); + } + + final ContentType ctype = contentType; + + return LocalTransaction.wrapReturn(() -> { + ContentType contentTypeToSave = ctype; + + // set to system folder if on system host or the host id of the folder it is on + List oldFields = fAPI.byContentTypeId(contentTypeToSave.id()); + + // Checks if the folder has been set, if so checks the host where that folder lives and set + // it. + if (UtilMethods.isSet(contentTypeToSave.folder()) && !contentTypeToSave.folder().equals(Folder.SYSTEM_FOLDER)) { + contentTypeToSave = ContentTypeBuilder.builder(contentTypeToSave) + .host(APILocator.getFolderAPI().find(contentTypeToSave.folder(), user, false).getHostId()).build(); + } else if (UtilMethods.isSet(contentTypeToSave.host())) {// If there is no folder set, check + // if the host has been set, if so + // set the folder to System Folder + contentTypeToSave = ContentTypeBuilder.builder(contentTypeToSave).folder(Folder.SYSTEM_FOLDER).build(); } - // check perms - Permissionable parent = contentType.getParentPermissionable(); - if (!perms.doesUserHavePermissions(parent, - "PARENT:" + PermissionAPI.PERMISSION_CAN_ADD_CHILDREN + ", STRUCTURES:" + PermissionAPI.PERMISSION_PUBLISH, - user)) { - throw new DotSecurityException( - "User-does-not-have-add-children-or-structure-permission-on-host-folder:" + parent); + if (!ctype.fields().isEmpty()) { + contentTypeToSave.constructWithFields(ctype.fields()); } - final ContentType ctype = contentType; + ContentType oldType = null; + try { + if (contentTypeToSave.id() != null) { + oldType = this.fac.find(contentTypeToSave.id()); + } + } catch (NotFoundInDbException notThere) { + // not logging, expected when inserting new from separate environment + } + + contentTypeToSave = this.fac.save(contentTypeToSave); - return LocalTransaction.wrapReturn(() -> { - ContentType contentTypeToSave = ctype; + if (oldType != null) { + if (fireUpdateIdentifiers(oldType.expireDateVar(), contentTypeToSave.expireDateVar())) { - // set to system folder if on system host or the host id of the folder it is on - List oldFields = fAPI.byContentTypeId(contentTypeToSave.id()); + IdentifierDateJob.triggerJobImmediately(oldType, user); + } else if (fireUpdateIdentifiers(oldType.publishDateVar(), contentTypeToSave.publishDateVar())) { - //Checks if the folder has been set, if so checks the host where that folder lives and set it. - if(UtilMethods.isSet(contentTypeToSave.folder()) && !contentTypeToSave.folder().equals(Folder.SYSTEM_FOLDER)){ - contentTypeToSave = ContentTypeBuilder.builder(contentTypeToSave) - .host(APILocator.getFolderAPI().find(contentTypeToSave.folder(), user, false).getHostId()).build(); - }else if(UtilMethods.isSet(contentTypeToSave.host())){//If there is no folder set, check if the host has been set, if so set the folder to System Folder - contentTypeToSave = ContentTypeBuilder.builder(contentTypeToSave).folder(Folder.SYSTEM_FOLDER).build(); + IdentifierDateJob.triggerJobImmediately(oldType, user); + } + perms.resetPermissionReferences(contentTypeToSave); + } + ActivityLogger.logInfo(getClass(), "Save ContentType Action", + "User " + user.getUserId() + "/" + user.getFullName() + " added ContentType " + contentTypeToSave.name() + + " to host id:" + contentTypeToSave.host()); + AdminLogger.log(getClass(), "ContentType", "ContentType saved : " + contentTypeToSave.name(), user); + + // update the existing content type fields + if (newFields != null) { + + Map varNamesCantDelete = new HashMap(); + + for (Field oldField : oldFields) { + if (!newFields.stream().anyMatch(f -> f.id().equals(oldField.id()))) { + if (!oldField.fixed()) { + Logger.info(this, "Deleting no longer needed Field: " + oldField.name() + " with ID: " + oldField.id() + + ", from Content Type: " + contentTypeToSave.name()); + + fAPI.delete(oldField); + } else { + Logger.info(this, "Can't delete Field because is fixed: " + oldField.name() + " with ID: " + oldField.id() + + ", from Content Type: " + contentTypeToSave.name()); + varNamesCantDelete.put(oldField.variable(), oldField); + } } + } - if ( !ctype.fields().isEmpty() ) { - contentTypeToSave.constructWithFields(ctype.fields()); + // for each field in the content type lets create it if doesn't exists and update its + // properties if it does + for (Field field : newFields) { + if (!varNamesCantDelete.containsKey(field.variable())) { + fAPI.save(field, APILocator.systemUser()); + } else { + // We replace the newField-ID with the oldField-ID in order to be able to update the + // Field + // instead of creating a new one due the different ID. We need to be sure new field has + // same variable and DB column. + Field oldField = varNamesCantDelete.get(field.variable()); + if (oldField.variable().equals(field.variable()) && oldField.dbColumn().equals(field.dbColumn())) { + + // Create a copy of the new Field with the oldField-ID, + field = FieldBuilder.builder(field).id(oldField.id()).build(); + fAPI.save(field, APILocator.systemUser()); + } else { + // If the field don't match on VariableName and DBColumn we log an error. + Logger.error(this, "Can't save Field with already existing VariableName: " + field.variable() + ", id: " + + field.id() + ", DBColumn: " + field.dbColumn()); + } } - ContentType oldType = null; - try { - if (contentTypeToSave.id() != null) { - oldType = this.fac.find(contentTypeToSave.id()); + if (newFieldVariables != null && !newFieldVariables.isEmpty()) { + for (FieldVariable fieldVariable : newFieldVariables) { + if (fieldVariable.fieldId().equals(field.inode())) { + fAPI.save(fieldVariable, APILocator.systemUser()); } - } catch (NotFoundInDbException notThere) { - // not logging, expected when inserting new from separate environment + } } + } + } - contentTypeToSave = this.fac.save(contentTypeToSave); - - if (oldType != null) { - if (fireUpdateIdentifiers(oldType.expireDateVar(), contentTypeToSave.expireDateVar())) { + return find(contentTypeToSave.id()); + }); + } - IdentifierDateJob.triggerJobImmediately(oldType, user); - } else if (fireUpdateIdentifiers(oldType.publishDateVar(), contentTypeToSave.publishDateVar())) { + @Override + public boolean updateModDate(ContentType type) throws DotDataException { + boolean updated = false; - IdentifierDateJob.triggerJobImmediately(oldType, user); - } - perms.resetPermissionReferences(contentTypeToSave); - } - ActivityLogger.logInfo(getClass(), "Save ContentType Action", - "User " + user.getUserId() + "/" + user.getFullName() - + " added ContentType " + contentTypeToSave.name() - + " to host id:" + contentTypeToSave.host()); - AdminLogger.log(getClass(), "ContentType", - "ContentType saved : " + contentTypeToSave.name(), user); - - //update the existing content type fields - if(newFields != null) { - - for (Field oldField : oldFields) { - if ( !newFields.stream().anyMatch( f -> f.id().equals(oldField.id()) ) && !oldField.fixed()) { - Logger.info(this, - "Deleting no longer needed Field: " + oldField.name() + - " with ID: " + oldField.id() + - ", from Content Type: " + contentTypeToSave.name()); - - fAPI.delete(oldField); - } - } + fac.updateModDate(type); - //for each field in the content type lets create it if doesn't exists and update its properties if it does - for( Field field : newFields ) { - fAPI.save(field, APILocator.systemUser()); - - if( newFieldVariables != null && !newFieldVariables.isEmpty() ){ - for(FieldVariable fieldVariable : newFieldVariables) { - if(fieldVariable.fieldId().equals(field.inode())) { - fAPI.save(fieldVariable, APILocator.systemUser()); - } - } - } - } - } + updated = true; - return find(contentTypeToSave.id()); - }); + return updated; } - - public boolean updateModDate(ContentType type){ - boolean updated = false; - - try { - fac.updateModDate(type); - updated=true; - } catch (DotDataException e) { - Logger.error(this, "Error can't update Content Type ("+type.id()+") mod_date field. "+e.getMessage()); - e.printStackTrace(); - } - return updated; - } - + @Override + public boolean updateModDate(Field field) throws DotDataException { + return this.updateModDate( fac.find( field.contentTypeId() ) ); + } } diff --git a/dotCMS/src/main/java/com/dotcms/contenttype/business/ContentTypeFactoryImpl.java b/dotCMS/src/main/java/com/dotcms/contenttype/business/ContentTypeFactoryImpl.java index 6df6178a2574..544efda9fb2a 100644 --- a/dotCMS/src/main/java/com/dotcms/contenttype/business/ContentTypeFactoryImpl.java +++ b/dotCMS/src/main/java/com/dotcms/contenttype/business/ContentTypeFactoryImpl.java @@ -222,10 +222,12 @@ public ContentType save(ContentType type) throws DotDataException { @Override public ContentType setAsDefault(ContentType type) throws DotDataException { - if (!type.equals(findDefaultType())) { + ContentType oldDefault= findDefaultType(); + if (!type.equals(oldDefault)) { LocalTransaction.wrapReturn(() -> { ContentType returnType = dbUpdateDefaultToTrue(type); - cache.clearCache(); + cache.remove(type); + cache.remove(oldDefault); return returnType; }); } diff --git a/dotCMS/src/main/java/com/dotcms/contenttype/business/FieldFactoryImpl.java b/dotCMS/src/main/java/com/dotcms/contenttype/business/FieldFactoryImpl.java index 1bfd297b9122..f6851bdc55a1 100644 --- a/dotCMS/src/main/java/com/dotcms/contenttype/business/FieldFactoryImpl.java +++ b/dotCMS/src/main/java/com/dotcms/contenttype/business/FieldFactoryImpl.java @@ -30,13 +30,10 @@ import com.dotcms.contenttype.transform.field.DbFieldVariableTransformer; import com.dotcms.repackage.org.apache.commons.lang.time.DateUtils; import com.dotmarketing.business.APILocator; -import com.dotmarketing.business.CacheLocator; -import com.dotmarketing.business.DotStateException; -import com.dotmarketing.business.DotValidationException; import com.dotmarketing.common.db.DotConnect; import com.dotmarketing.db.LocalTransaction; import com.dotmarketing.exception.DotDataException; -import com.dotmarketing.exception.DotSecurityException; + import com.dotmarketing.util.Config; import com.dotmarketing.util.Logger; import com.dotmarketing.util.StringUtils; @@ -112,53 +109,35 @@ public FieldVariable loadVariable(String id) throws DotDataException { @Override public FieldVariable save(FieldVariable fieldVar) throws DotDataException { - FieldVariable newVar = LocalTransaction.wrapReturn(() -> { - return upsertFieldVariable(fieldVar); + return LocalTransaction.wrapReturn(() -> { + FieldVariable fv = upsertFieldVariable(fieldVar); + Field f = byId(fieldVar.fieldId()); + APILocator.getContentTypeAPI(APILocator.systemUser()).updateModDate(f); + return fv; }); - Field f = byId(fieldVar.fieldId()); - ContentType t; - try { - t = APILocator.getContentTypeAPI(APILocator.systemUser()).find(f.contentTypeId()); - if (t != null) { - CacheLocator.getContentTypeCache2().remove(t); - } - } catch (DotSecurityException e) { - throw new DotStateException(e); - } - - return newVar; - } @Override public void delete(FieldVariable fieldVar) throws DotDataException { LocalTransaction.wrapReturn(() -> { deleteFieldVarInDb(fieldVar); + Field f = byId(fieldVar.fieldId()); + APILocator.getContentTypeAPI(APILocator.systemUser()).updateModDate(f); return null; }); + - Field f = byId(fieldVar.fieldId()); - ContentType t; - try { - t = APILocator.getContentTypeAPI(APILocator.systemUser()).find(f.contentTypeId()); - if (t != null) { - CacheLocator.getContentTypeCache2().remove(t); - } - } catch (DotSecurityException e) { - throw new DotStateException(e); - } } @Override public Field save(final Field throwAwayField) throws DotDataException { - Field f = LocalTransaction.wrapReturn(() -> { - return dbSaveUpdate(throwAwayField); + return LocalTransaction.wrapReturn(() -> { + Field field = dbSaveUpdate(throwAwayField); + APILocator.getContentTypeAPI(APILocator.systemUser()).updateModDate(field); + return field; }); - ContentType t = CacheLocator.getContentTypeCache2().byVarOrInode(f.contentTypeId()); - if (t != null) - CacheLocator.getContentTypeCache2().remove(t); - return f; + } @@ -209,27 +188,15 @@ private Field normalizeData(final Field throwAwayField) throws DotDataException - - - private Field dbSaveUpdate(final Field throwAwayField) throws DotDataException { - - - - - - FieldBuilder builder = FieldBuilder.builder(throwAwayField); Date modDate = DateUtils.round(new Date(), Calendar.SECOND); builder.modDate(modDate); - - - Field oldField = null; try {