From 20bfa4f00d23d61b75730a31199a305103622e29 Mon Sep 17 00:00:00 2001
From: srosse <stephane.rosse@frentix.com>
Date: Mon, 20 May 2019 18:12:46 +0200
Subject: [PATCH] OO-4061: allow longer note

---
 .../java/org/olat/note/NoteController.java    |  36 ++---
 src/main/java/org/olat/note/NoteImpl.hbm.xml  |  49 -------
 src/main/java/org/olat/note/NoteImpl.java     | 126 +++++++++++++++---
 src/main/java/org/olat/note/NoteManager.java  |   8 +-
 .../_spring/databaseUpgradeContext.xml        |   4 +
 src/main/resources/META-INF/persistence.xml   |   2 +-
 .../mysql/alter_12_5_x_to_12_5_24.sql         |   0
 .../oracle/alter_12_5_x_to_12_5_24.sql        |   4 +
 .../postgresql/alter_12_5_x_to_12_5_24.sql    |   0
 src/test/java/org/olat/note/NoteTest.java     |  15 +++
 10 files changed, 144 insertions(+), 100 deletions(-)
 delete mode 100644 src/main/java/org/olat/note/NoteImpl.hbm.xml
 create mode 100644 src/main/resources/database/mysql/alter_12_5_x_to_12_5_24.sql
 create mode 100644 src/main/resources/database/oracle/alter_12_5_x_to_12_5_24.sql
 create mode 100644 src/main/resources/database/postgresql/alter_12_5_x_to_12_5_24.sql

diff --git a/src/main/java/org/olat/note/NoteController.java b/src/main/java/org/olat/note/NoteController.java
index 8428ceefe7c..37d7d50a5c8 100644
--- a/src/main/java/org/olat/note/NoteController.java
+++ b/src/main/java/org/olat/note/NoteController.java
@@ -58,6 +58,8 @@ import org.springframework.beans.factory.annotation.Autowired;
  * 
  */
 public class NoteController extends FormBasicController implements GenericEventListener {
+	
+	private static final int NOTE_MAX_LENGTH = 400000;
 
 	private Note n;
 	private EventBus sec;
@@ -129,7 +131,7 @@ public class NoteController extends FormBasicController implements GenericEventL
 		
 		noteField = uifactory.addRichTextElementForStringData("noteField", null, n.getNoteText(), 20, -1, false, null, null, formLayout, ureq.getUserSession(), getWindowControl());
 		noteField.setEnabled(false);
-		noteField.setMaxLength(4000);
+		noteField.setMaxLength(NOTE_MAX_LENGTH);
 
 		submitButton = uifactory.addFormSubmitButton("submit", formLayout);
 		submitButton.setVisible(false);
@@ -147,18 +149,12 @@ public class NoteController extends FormBasicController implements GenericEventL
 		}
 	}
 
-	/**
-	 * @see org.olat.core.gui.control.DefaultController#doDispose(boolean)
-	 */
 	@Override
 	protected void doDispose() {
 		sec.deregisterFor(this, OresHelper.lookupType(Note.class));
 	}
 
-	/**
-	 * 
-	 * @see org.olat.core.util.event.GenericEventListener#event(org.olat.core.gui.control.Event)
-	 */
+	@Override
 	public void event(Event event) {
 		if (event instanceof OLATResourceableJustBeforeDeletedEvent) {
 			OLATResourceableJustBeforeDeletedEvent bdev = (OLATResourceableJustBeforeDeletedEvent) event;
@@ -173,15 +169,16 @@ public class NoteController extends FormBasicController implements GenericEventL
 
 	@Override
 	protected boolean validateFormLogic(UserRequest ureq) {
+		boolean allOk = super.validateFormLogic(ureq);
+		
 		String text = noteField.getValue();
-		boolean allOk = true;
-		if(text.length() <= 4000) {
-			noteField.clearError();
-		} else {
-			noteField.setErrorKey("input.toolong", new String[]{"4000"});
-			allOk = false;
+		noteField.clearError();
+		if(text.length() > NOTE_MAX_LENGTH) {
+			noteField.setErrorKey("input.toolong", new String[]{ Integer.toString(NOTE_MAX_LENGTH) });
+			allOk &= false;
 		}
-		return allOk && super.validateFormLogic(ureq);
+		
+		return allOk;
 	}
 
 	@Override
@@ -197,17 +194,10 @@ public class NoteController extends FormBasicController implements GenericEventL
 		noteField.setEnabled(false);
 	}
 
-	/**
-	 * @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#formInnerEvent(org.olat.core.gui.UserRequest,
-	 *      org.olat.core.gui.components.form.flexible.FormItem,
-	 *      org.olat.core.gui.components.form.flexible.impl.FormEvent)
-	 */
 	@Override
 	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
-		// persisting: see formOK
-		
 		// If the user clicked the edit button, set the rich text input field to enabled and hide the edit button.
-		if ((source == editButton) && (editButton.isEnabled())) {
+		if (source == editButton && editButton.isEnabled()) {
 			noteField.setEnabled(true);
 			editButton.setVisible(false);
 			submitButton.setVisible(true);
diff --git a/src/main/java/org/olat/note/NoteImpl.hbm.xml b/src/main/java/org/olat/note/NoteImpl.hbm.xml
deleted file mode 100644
index ab87e948509..00000000000
--- a/src/main/java/org/olat/note/NoteImpl.hbm.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE hibernate-mapping PUBLIC 
-        "-//Hibernate/Hibernate Mapping DTD//EN"
-        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
-
-<hibernate-mapping default-lazy="false">
-
-  <!-- Can't name the class user, clashes with postgres database -->
-  <class name="org.olat.note.NoteImpl" table="o_note">
-    
-    <id name="key" column="note_id" type="long" unsaved-value="null">
-		<generator class="enhanced-sequence">
-			<param name="sequence_name">hibernate_unique_key</param>
-			<param name="force_table_use">true</param>
-			<param name="optimizer">legacy-hilo</param>
-			<param name="value_column">next_hi</param>
-			<param name="increment_size">32767</param>
-			<param name="initial_value">32767</param>
-		</generator>
-    </id>
-
-	<version name="version" access="field" column="version" type="int"/>
-	<property  name="lastModified" column="lastmodified" type="timestamp" />
-	<property  name="creationDate" column="creationdate" type="timestamp" />
-  	
-  	<many-to-one name="owner" class="org.olat.basesecurity.IdentityImpl" outer-join="auto" cascade="none">  
-		<column name="owner_id" not-null="false" index="owner_idx"/>    	
-  	</many-to-one>
-  
-  	<property name="resourceTypeName"	type="string">
-  		<column name="resourcetypename" length="50" not-null="true" index="restype_idx0"/>
-  	</property>
-    
-    <property name="resourceTypeId"	type="long">
-    	<column name="resourcetypeid" not-null="true" index="resid_idx2"/>
-    </property>
-    
-	<property name="subtype" column="sub_type" unique="false" type="string" not-null="false" length="50"/>  
- 
-    <property name="noteTitle" column="notetitle" unique="false" type="string" not-null="false" length="255"/>
-    
-    <property name="noteText" unique="false" type="string" not-null="false">
-    	<column name="notetext" length="16777210"/>
-	</property> 
-    
-  </class>  
-
-</hibernate-mapping>
-
diff --git a/src/main/java/org/olat/note/NoteImpl.java b/src/main/java/org/olat/note/NoteImpl.java
index bde2dfbde8e..f1650ca2021 100644
--- a/src/main/java/org/olat/note/NoteImpl.java
+++ b/src/main/java/org/olat/note/NoteImpl.java
@@ -27,8 +27,25 @@ package org.olat.note;
 
 import java.util.Date;
 
-import org.olat.core.commons.persistence.PersistentObject;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.Version;
+
+import org.hibernate.annotations.GenericGenerator;
+import org.hibernate.annotations.Parameter;
+import org.olat.basesecurity.IdentityImpl;
+import org.olat.core.id.CreateInfo;
 import org.olat.core.id.Identity;
+import org.olat.core.id.Persistable;
 import org.olat.core.logging.AssertException;
 
 /**
@@ -37,19 +54,55 @@ import org.olat.core.logging.AssertException;
  * 
  * @author Alexander Schneider
  */
-public class NoteImpl extends PersistentObject implements Note {
+@Entity(name="note")
+@Table(name="o_note")
+@NamedQueries({
+	@NamedQuery(name="noteByOwner", query="select n from note as n inner join fetch n.owner as noteowner where noteowner.key=:noteowner"),
+	@NamedQuery(name="noteByOwnerAndResource", query="select n from note as n where n.owner.key=:ownerKey and n.resourceTypeName=:resName and n.resourceTypeId=:resId")
+})
+public class NoteImpl implements Note, Persistable, CreateInfo {
 
 	private static final long serialVersionUID = -403450817851666464L;
+	private static final int RESOURCETYPENAME_MAXLENGTH = 50;
+	private static final int SUBTYPE_MAXLENGTH = 50;
 	
-	private Identity owner;
+	@Id
+	@GeneratedValue(generator = "system-uuid")
+	@GenericGenerator(name = "system-uuid", strategy = "enhanced-sequence", parameters={
+		@Parameter(name="sequence_name", value="hibernate_unique_key"),
+		@Parameter(name="force_table_use", value="true"),
+		@Parameter(name="optimizer", value="legacy-hilo"),
+		@Parameter(name="value_column", value="next_hi"),
+		@Parameter(name="increment_size", value="32767"),
+		@Parameter(name="initial_value", value="32767")
+	})
+	@Column(name="note_id", nullable=false, unique=true, insertable=true, updatable=false)
+	private Long key;
+	@Version
+	private int version = 0;
+	
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="creationdate", nullable=false, insertable=true, updatable=false)
+	private Date creationDate;
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="lastmodified", nullable=false, insertable=true, updatable=true)
+	private Date lastModified;
+	
+	@Column(name="resourcetypename", nullable=false, insertable=true, updatable=false)
 	private String resourceTypeName;
+	@Column(name="resourcetypeid", nullable=false, insertable=true, updatable=false)
 	private Long resourceTypeId;
+	@Column(name="sub_type", nullable=true, insertable=true, updatable=false)
 	private String subtype;
+
+	@Column(name="notetitle", nullable=true, insertable=true, updatable=true)
 	private String noteTitle;
+	@Column(name="notetext", nullable=true, insertable=true, updatable=true)
 	private String noteText;
-	private Date lastModified;
-	private static final int RESOURCETYPENAME_MAXLENGTH = 50;
-	private static final int SUBTYPE_MAXLENGTH = 50;
+	
+	@OneToOne(targetEntity=IdentityImpl.class)
+	@JoinColumn(name="owner_id", nullable=false, insertable=true, updatable=false)
+	private Identity owner;
 
 	/**
 	 * Default construcor
@@ -58,9 +111,38 @@ public class NoteImpl extends PersistentObject implements Note {
 	// nothing to do
 	}
 
+	@Override
+	public Long getKey() {
+		return key;
+	}
+
+	public void setKey(Long key) {
+		this.key = key;
+	}
+
+	@Override
+	public Date getCreationDate() {
+		return creationDate;
+	}
+
+	public void setCreationDate(Date creationDate) {
+		this.creationDate = creationDate;
+	}
+
+	@Override
+	public Date getLastModified() {
+		return lastModified;
+	}
+
+	@Override
+	public void setLastModified(Date date) {
+		this.lastModified = date;
+	}
+
 	/**
 	 * @return Returns the noteText.
 	 */
+	@Override
 	public String getNoteText() {
 		return noteText;
 	}
@@ -68,6 +150,7 @@ public class NoteImpl extends PersistentObject implements Note {
 	/**
 	 * @param noteText The noteText to set.
 	 */
+	@Override
 	public void setNoteText(String noteText) {
 		this.noteText = noteText;
 	}
@@ -75,6 +158,7 @@ public class NoteImpl extends PersistentObject implements Note {
 	/**
 	 * @return Returns the noteTitle.
 	 */
+	@Override
 	public String getNoteTitle() {
 		return noteTitle;
 	}
@@ -82,6 +166,7 @@ public class NoteImpl extends PersistentObject implements Note {
 	/**
 	 * @param noteTitle The noteTitle to set.
 	 */
+	@Override
 	public void setNoteTitle(String noteTitle) {
 		this.noteTitle = noteTitle;
 	}
@@ -89,6 +174,7 @@ public class NoteImpl extends PersistentObject implements Note {
 	/**
 	 * @return Returns the owner.
 	 */
+	@Override
 	public Identity getOwner() {
 		return owner;
 	}
@@ -96,6 +182,7 @@ public class NoteImpl extends PersistentObject implements Note {
 	/**
 	 * @param owner The owner to set.
 	 */
+	@Override
 	public void setOwner(Identity owner) {
 		this.owner = owner;
 	}
@@ -103,6 +190,7 @@ public class NoteImpl extends PersistentObject implements Note {
 	/**
 	 * @return Returns the resourceTypeId.
 	 */
+	@Override
 	public Long getResourceTypeId() {
 		return resourceTypeId;
 	}
@@ -110,6 +198,7 @@ public class NoteImpl extends PersistentObject implements Note {
 	/**
 	 * @param resourceTypeId The resourceTypeId to set.
 	 */
+	@Override
 	public void setResourceTypeId(Long resourceTypeId) {
 		this.resourceTypeId = resourceTypeId;
 	}
@@ -117,6 +206,7 @@ public class NoteImpl extends PersistentObject implements Note {
 	/**
 	 * @return Returns the resourceTypeName.
 	 */
+	@Override
 	public String getResourceTypeName() {
 		return resourceTypeName;
 	}
@@ -124,6 +214,7 @@ public class NoteImpl extends PersistentObject implements Note {
 	/**
 	 * @param resourceTypeName The resourceTypeName to set.
 	 */
+	@Override
 	public void setResourceTypeName(String resourceTypeName) {
 		if (resourceTypeName.length() > RESOURCETYPENAME_MAXLENGTH)
 			throw new AssertException("resourcetypename in o_note too long");
@@ -133,6 +224,7 @@ public class NoteImpl extends PersistentObject implements Note {
 	/**
 	 * @return Returns the subtype.
 	 */
+	@Override
 	public String getSubtype() {
 		return subtype;
 	}
@@ -140,28 +232,13 @@ public class NoteImpl extends PersistentObject implements Note {
 	/**
 	 * @param subtype The subtype to set.
 	 */
+	@Override
 	public void setSubtype(String subtype) {
 		if (subtype != null && subtype.length() > SUBTYPE_MAXLENGTH)
 			throw new AssertException("subtype of o_note too long");
 		this.subtype = subtype;
 	}
 
-	/**
-	 * 
-	 * @see org.olat.core.id.ModifiedInfo#getLastModified()
-	 */
-	public Date getLastModified() {
-		return lastModified;
-	}
-
-	/**
-	 * 
-	 * @see org.olat.core.id.ModifiedInfo#setLastModified(java.util.Date)
-	 */
-	public void setLastModified(Date date) {
-		this.lastModified = date;
-	}
-
 	@Override
 	public int hashCode() {
 		return getKey() == null ? 2609815 : getKey().hashCode();
@@ -178,4 +255,9 @@ public class NoteImpl extends PersistentObject implements Note {
 		}
 		return false;
 	}
+
+	@Override
+	public boolean equalsByPersistableKey(Persistable persistable) {
+		return equals(persistable);
+	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/note/NoteManager.java b/src/main/java/org/olat/note/NoteManager.java
index 0547850a284..ea3ab7e4730 100644
--- a/src/main/java/org/olat/note/NoteManager.java
+++ b/src/main/java/org/olat/note/NoteManager.java
@@ -102,9 +102,8 @@ public class NoteManager implements UserDataDeletable, UserDataExportable {
 	 * @return the note
 	 */
 	private Note findNote(IdentityRef owner, String resourceTypeName, Long resourceTypeId) {
-
-		String query = "select n from org.olat.note.NoteImpl as n where n.owner.key=:ownerKey and n.resourceTypeName=:resName and n.resourceTypeId=:resId";
-		List<Note> notes = dbInstance.getCurrentEntityManager().createQuery(query, Note.class)
+		List<Note> notes = dbInstance.getCurrentEntityManager()
+				.createNamedQuery("noteByOwnerAndResource", Note.class)
 				.setParameter("ownerKey", owner.getKey())
 				.setParameter("resName", resourceTypeName)
 				.setParameter("resId", resourceTypeId)
@@ -120,9 +119,8 @@ public class NoteManager implements UserDataDeletable, UserDataExportable {
 	 * @return a list of notes belonging to the owner
 	 */
 	public List<Note> listUserNotes(IdentityRef owner) {
-		String query = "select n from org.olat.note.NoteImpl as n inner join fetch n.owner as noteowner where noteowner.key=:noteowner";
 		return dbInstance.getCurrentEntityManager()
-				.createQuery(query, Note.class).
+				.createNamedQuery("noteByOwner", Note.class).
 				setParameter("noteowner", owner.getKey())
 				.getResultList();
 	}
diff --git a/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml b/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml
index 39d27d93e49..9d3fa4d34b6 100644
--- a/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml
+++ b/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml
@@ -184,6 +184,10 @@
 					<constructor-arg index="0" value="OLAT_12.5.14" />
 					<property name="alterDbStatements" value="alter_12_5_x_to_12_5_14.sql" />
 				</bean>
+				<bean id="database_upgrade_12_5_24" class="org.olat.upgrade.DatabaseUpgrade">
+					<constructor-arg index="0" value="OLAT_12.5.24" />
+					<property name="alterDbStatements" value="alter_12_5_x_to_12_5_24.sql" />
+				</bean>
 			</list>
 		</property>
 	</bean>
diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml
index 315305a0065..13b644f2d66 100644
--- a/src/main/resources/META-INF/persistence.xml
+++ b/src/main/resources/META-INF/persistence.xml
@@ -12,7 +12,6 @@
 		<mapping-file>de/bps/olat/modules/cl/Checkpoint.hbm.xml</mapping-file>
 		<mapping-file>org/olat/ims/qti/QTIResult.hbm.xml</mapping-file>
 		<mapping-file>org/olat/ims/qti/QTIResultSet.hbm.xml</mapping-file>
-		<mapping-file>org/olat/note/NoteImpl.hbm.xml</mapping-file>
 		<mapping-file>org/olat/commons/lifecycle/LifeCycleEntry.hbm.xml</mapping-file>
 		<mapping-file>org/olat/commons/coordinate/cluster/lock/LockImpl.hbm.xml</mapping-file>
 		<mapping-file>org/olat/group/area/BGAreaImpl.hbm.xml</mapping-file>
@@ -122,6 +121,7 @@
 		<class>org.olat.group.model.GroupToBusinessGroup</class>
 		<class>org.olat.group.model.BusinessGroupToSearch</class>
 		<class>org.olat.group.BusinessGroupImpl</class>
+		<class>org.olat.note.NoteImpl</class>
 		<class>org.olat.registration.TemporaryKeyImpl</class>
 		<class>org.olat.repository.RepositoryEntry</class>
 		<class>org.olat.repository.model.RepositoryEntryToGroupRelation</class>
diff --git a/src/main/resources/database/mysql/alter_12_5_x_to_12_5_24.sql b/src/main/resources/database/mysql/alter_12_5_x_to_12_5_24.sql
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/src/main/resources/database/oracle/alter_12_5_x_to_12_5_24.sql b/src/main/resources/database/oracle/alter_12_5_x_to_12_5_24.sql
new file mode 100644
index 00000000000..8ab42174cea
--- /dev/null
+++ b/src/main/resources/database/oracle/alter_12_5_x_to_12_5_24.sql
@@ -0,0 +1,4 @@
+alter table o_note add ( temp clob );
+update o_note set temp=notetext, notetext=null;
+alter table o_note drop column notetext;
+alter table o_note rename column temp to notetext;
diff --git a/src/main/resources/database/postgresql/alter_12_5_x_to_12_5_24.sql b/src/main/resources/database/postgresql/alter_12_5_x_to_12_5_24.sql
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/src/test/java/org/olat/note/NoteTest.java b/src/test/java/org/olat/note/NoteTest.java
index d670fb2a30c..e86500ff808 100644
--- a/src/test/java/org/olat/note/NoteTest.java
+++ b/src/test/java/org/olat/note/NoteTest.java
@@ -97,4 +97,19 @@ public class NoteTest extends OlatTestCase {
 	    Assert.assertEquals("Important", reloadedNote.getNoteTitle());
 	    Assert.assertEquals("Cool update with new features", reloadedNote.getNoteText());
 	}
+	
+	@Test
+	public void findNote() {
+		Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("note-2-");
+	    OLATResource resource = JunitTestHelper.createRandomResource();
+		Note note = noteManager.loadNoteOrCreateInRAM(identity, resource.getResourceableTypeName(), resource.getResourceableId());
+		note.setNoteTitle("Very important");
+	    note.setNoteText("Critical update with new features");
+	    noteManager.saveNote(note);
+	    dbInstance.commitAndCloseSession();
+	    
+	    Note reloadedNote = noteManager.loadNoteOrCreateInRAM(identity, resource.getResourceableTypeName(), resource.getResourceableId());
+	    Assert.assertNotNull(reloadedNote);
+	    Assert.assertEquals(note, reloadedNote);
+	}
 }
-- 
GitLab