--- /dev/null
+class AClass{
+}
--- /dev/null
+class Test {
+ AClass field;
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4" relativePaths="true">
+ <component name="AntConfiguration">
+ <defaultAnt bundledAnt="true" />
+ </component>
+ <component name="BuildJarProjectSettings">
+ <option name="BUILD_JARS_ON_MAKE" value="false" />
+ </component>
+ <component name="CodeStyleProjectProfileManger">
+ <option name="PROJECT_PROFILE" />
+ <option name="USE_PROJECT_LEVEL_SETTINGS" value="false" />
+ <scopes />
+ <profiles />
+ </component>
+ <component name="CodeStyleSettingsManager">
+ <option name="PER_PROJECT_SETTINGS" />
+ <option name="USE_PER_PROJECT_SETTINGS" value="false" />
+ </component>
+ <component name="CompilerConfiguration">
+ <option name="DEFAULT_COMPILER" value="Javac" />
+ <option name="DEPLOY_AFTER_MAKE" value="0" />
+ <resourceExtensions>
+ <entry name=".+\.(properties|xml|html|dtd|tld)" />
+ <entry name=".+\.(gif|png|jpeg|jpg)" />
+ </resourceExtensions>
+ <wildcardResourcePatterns>
+ <entry name="?*.properties" />
+ <entry name="?*.xml" />
+ <entry name="?*.gif" />
+ <entry name="?*.png" />
+ <entry name="?*.jpeg" />
+ <entry name="?*.jpg" />
+ <entry name="?*.html" />
+ <entry name="?*.dtd" />
+ <entry name="?*.tld" />
+ </wildcardResourcePatterns>
+ </component>
+ <component name="DataSourceManagerImpl" />
+ <component name="DependenciesAnalyzeManager">
+ <option name="myForwardDirection" value="false" />
+ </component>
+ <component name="DependencyValidationManager" />
+ <component name="EclipseCompilerSettings">
+ <option name="DEBUGGING_INFO" value="true" />
+ <option name="GENERATE_NO_WARNINGS" value="true" />
+ <option name="DEPRECATION" value="false" />
+ <option name="ADDITIONAL_OPTIONS_STRING" value="" />
+ <option name="MAXIMUM_HEAP_SIZE" value="128" />
+ </component>
+ <component name="EclipseEmbeddedCompilerSettings">
+ <option name="DEBUGGING_INFO" value="true" />
+ <option name="GENERATE_NO_WARNINGS" value="true" />
+ <option name="DEPRECATION" value="false" />
+ <option name="ADDITIONAL_OPTIONS_STRING" value="" />
+ <option name="MAXIMUM_HEAP_SIZE" value="128" />
+ </component>
+ <component name="EntryPointsManager">
+ <entry_points />
+ </component>
+ <component name="ExportToHTMLSettings">
+ <option name="PRINT_LINE_NUMBERS" value="false" />
+ <option name="OPEN_IN_BROWSER" value="false" />
+ <option name="OUTPUT_DIRECTORY" />
+ </component>
+ <component name="GUI Designer component loader factory" />
+ <component name="InspectionProjectProfileManager">
+ <option name="PROJECT_PROFILE" value="Project Default" />
+ <option name="USE_PROJECT_LEVEL_SETTINGS" value="false" />
+ <scopes />
+ <profiles>
+ <profile version="1.0" is_locked="false">
+ <option name="myName" value="Project Default" />
+ <option name="myLocal" value="false" />
+ </profile>
+ </profiles>
+ </component>
+ <component name="JavacSettings">
+ <option name="DEBUGGING_INFO" value="true" />
+ <option name="GENERATE_NO_WARNINGS" value="false" />
+ <option name="DEPRECATION" value="true" />
+ <option name="ADDITIONAL_OPTIONS_STRING" value="" />
+ <option name="MAXIMUM_HEAP_SIZE" value="128" />
+ </component>
+ <component name="JavadocGenerationManager">
+ <option name="OUTPUT_DIRECTORY" />
+ <option name="OPTION_SCOPE" value="protected" />
+ <option name="OPTION_HIERARCHY" value="true" />
+ <option name="OPTION_NAVIGATOR" value="true" />
+ <option name="OPTION_INDEX" value="true" />
+ <option name="OPTION_SEPARATE_INDEX" value="true" />
+ <option name="OPTION_DOCUMENT_TAG_USE" value="false" />
+ <option name="OPTION_DOCUMENT_TAG_AUTHOR" value="false" />
+ <option name="OPTION_DOCUMENT_TAG_VERSION" value="false" />
+ <option name="OPTION_DOCUMENT_TAG_DEPRECATED" value="true" />
+ <option name="OPTION_DEPRECATED_LIST" value="true" />
+ <option name="OTHER_OPTIONS" value="" />
+ <option name="HEAP_SIZE" />
+ <option name="LOCALE" />
+ <option name="OPEN_IN_BROWSER" value="true" />
+ </component>
+ <component name="JikesSettings">
+ <option name="JIKES_PATH" value="" />
+ <option name="DEBUGGING_INFO" value="true" />
+ <option name="DEPRECATION" value="true" />
+ <option name="GENERATE_NO_WARNINGS" value="false" />
+ <option name="IS_EMACS_ERRORS_MODE" value="true" />
+ <option name="ADDITIONAL_OPTIONS_STRING" value="" />
+ </component>
+ <component name="LogConsolePreferences">
+ <option name="FILTER_ERRORS" value="false" />
+ <option name="FILTER_WARNINGS" value="false" />
+ <option name="FILTER_INFO" value="true" />
+ <option name="CUSTOM_FILTER" />
+ </component>
+ <component name="Palette2">
+ <group name="Swing">
+ <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
+ </item>
+ <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
+ </item>
+ <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
+ <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
+ <initial-values>
+ <property name="text" value="Button" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="RadioButton" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="CheckBox" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="Label" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+ <preferred-size width="200" height="200" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+ <preferred-size width="200" height="200" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
+ </item>
+ <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
+ <preferred-size width="-1" height="20" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
+ </item>
+ <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
+ </item>
+ </group>
+ </component>
+ <component name="ProjectModuleManager">
+ <modules>
+ <module fileurl="file://$PROJECT_DIR$/test1/test1.iml" filepath="$PROJECT_DIR$/test1/test1.iml" />
+ <module fileurl="file://$PROJECT_DIR$/test2/test2.iml" filepath="$PROJECT_DIR$/test2/test2.iml" />
+ <module fileurl="file://$PROJECT_DIR$/test3/test3.iml" filepath="$PROJECT_DIR$/test3/test3.iml" />
+ </modules>
+ </component>
+ <component name="ProjectRootManager" version="2" assert-keyword="true" jdk-15="true" project-jdk-name="1.5" project-jdk-type="JavaSDK">
+ <output url="file://$PROJECT_DIR$/classes" />
+ </component>
+ <component name="ProjectRunConfigurationManager" />
+ <component name="RmicSettings">
+ <option name="IS_EANABLED" value="false" />
+ <option name="DEBUGGING_INFO" value="true" />
+ <option name="GENERATE_NO_WARNINGS" value="false" />
+ <option name="GENERATE_IIOP_STUBS" value="false" />
+ <option name="ADDITIONAL_OPTIONS_STRING" value="" />
+ </component>
+ <component name="StarteamVcsAdapter" />
+ <component name="VssVcs" />
+ <component name="libraryTable" />
+ <component name="uidesigner-configuration">
+ <option name="INSTRUMENT_CLASSES" value="true" />
+ <option name="COPY_FORMS_RUNTIME_TO_OUTPUT" value="true" />
+ <option name="DEFAULT_LAYOUT_MANAGER" value="GridLayoutManager" />
+ </component>
+ <UsedPathMacros />
+</project>
+
--- /dev/null
+package com.test;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: cdr
+ * Date: Aug 14, 2006
+ * Time: 3:35:18 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public interface TestI {//jjjkjh kljh lk
+ void test(/* */);
+}
--- /dev/null
+package com.test;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: cdr
+ * Date: Aug 14, 2006
+ * Time: 3:35:52 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class TestIImpl1 implements TestI {
+ public void test() {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
--- /dev/null
+package com.test;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: cdr
+ * Date: Aug 14, 2006
+ * Time: 3:36:03 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class TestIImpl2 implements TestI {
+ public void test() {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<module version="4" relativePaths="true" type="JAVA_MODULE">
+ <component name="ModuleRootManager" />
+ <component name="NewModuleRootManager" inherit-compiler-output="true">
+ <exclude-output />
+ <content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ <orderEntryProperties />
+ </component>
+</module>
+
--- /dev/null
+package com.test;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: cdr
+ * Date: Aug 14, 2006
+ * Time: 3:35:11 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public interface TestI {
+}
--- /dev/null
+package com.test;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: cdr
+ * Date: Aug 14, 2006
+ * Time: 3:36:22 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class TestIImpl1 implements TestI {
+}
--- /dev/null
+package com.test;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: cdr
+ * Date: Aug 14, 2006
+ * Time: 3:36:28 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class TestIImpl3 implements TestI {
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<module version="4" relativePaths="true" type="JAVA_MODULE">
+ <component name="ModuleRootManager" />
+ <component name="NewModuleRootManager" inherit-compiler-output="true">
+ <exclude-output />
+ <content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ <orderEntryProperties />
+ </component>
+</module>
+
--- /dev/null
+package com.test;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: cdr
+ * Date: Aug 14, 2006
+ * Time: 3:35:03 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public interface TestI {
+}
--- /dev/null
+package com.test;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: cdr
+ * Date: Aug 14, 2006
+ * Time: 3:36:36 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class TestIImpl1 implements TestI {
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<module version="4" relativePaths="true" type="JAVA_MODULE">
+ <component name="ModuleRootManager" />
+ <component name="NewModuleRootManager" inherit-compiler-output="true">
+ <exclude-output />
+ <content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ <orderEntryProperties />
+ </component>
+</module>
+
--- /dev/null
+package test;
+class A {
+ void methodOfClassFromLib1() {
+ }
+}
\ No newline at end of file
--- /dev/null
+package test;
+class A {
+ void methodOfClassFromLib2() {
+ }
+}
\ No newline at end of file
--- /dev/null
+package com.intellij.navigation;
+
+import com.intellij.JavaTestUtil;
+import com.intellij.codeInsight.CodeInsightTestCase;
+import com.intellij.codeInsight.navigation.ClassImplementationsSearch;
+import com.intellij.codeInsight.navigation.MethodImplementationsSearch;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleManager;
+import com.intellij.openapi.module.impl.ModuleManagerImpl;
+import com.intellij.openapi.project.ex.ProjectManagerEx;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.util.CommonProcessors;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author cdr
+ */
+public class GotoImplementationTest extends CodeInsightTestCase {
+
+ private static Collection<PsiClass> getClassImplementations(final PsiClass psiClass) {
+ CommonProcessors.CollectProcessor<PsiClass> processor = new CommonProcessors.CollectProcessor<PsiClass>();
+ ClassImplementationsSearch.processImplementations(psiClass, processor);
+
+ return processor.getResults();
+ }
+
+ @Override
+ protected void setUpProject() throws Exception {
+ final String root = JavaTestUtil.getJavaTestDataPath() + "/codeInsight/navigation/alexProject";
+ VirtualFile vfsRoot = LocalFileSystem.getInstance().findFileByPath(FileUtil.toSystemIndependentName(root));
+
+ VirtualFile projectFile = vfsRoot.findChild("test.ipr");
+ myProject = ProjectManagerEx.getInstanceEx().loadProject(projectFile.getPath());
+
+ simulateProjectOpen();
+ ProjectManagerEx.getInstanceEx().setCurrentTestProject(myProject);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ ((ModuleManagerImpl)ModuleManager.getInstance(myProject)).projectClosed();
+ super.tearDown();
+ }
+
+ public void test() throws Exception {
+
+ ModuleManager moduleManager = ModuleManager.getInstance(getProject());
+ Module[] modules = moduleManager.getModules();
+ assertEquals(3, modules.length);
+
+ Module module1 = moduleManager.findModuleByName("test1");
+ Module module2 = moduleManager.findModuleByName("test2");
+ Module module3 = moduleManager.findModuleByName("test3");
+ PsiClass test1 = myJavaFacade.findClass("com.test.TestI", GlobalSearchScope.moduleScope(module1));
+ PsiClass test2 = myJavaFacade.findClass("com.test.TestI", GlobalSearchScope.moduleScope(module2));
+ PsiClass test3 = myJavaFacade.findClass("com.test.TestI", GlobalSearchScope.moduleScope(module3));
+ HashSet<PsiClass> expectedImpls1 = new HashSet<PsiClass>(Arrays.asList(
+ myJavaFacade.findClass("com.test.TestIImpl1", GlobalSearchScope.moduleScope(module1)),
+ myJavaFacade.findClass("com.test.TestIImpl2", GlobalSearchScope.moduleScope(module1))
+ ));
+ assertEquals(expectedImpls1, new HashSet<PsiClass>(getClassImplementations(test1)));
+
+ PsiMethod psiMethod = test1.findMethodsByName("test", false)[0];
+ Set<PsiMethod> expectedMethodImpl1 = new HashSet<PsiMethod>(Arrays.asList(
+ myJavaFacade.findClass("com.test.TestIImpl1", GlobalSearchScope.moduleScope(module1)).findMethodsByName("test",false)[0],
+ myJavaFacade.findClass("com.test.TestIImpl2", GlobalSearchScope.moduleScope(module1)).findMethodsByName("test",false)[0]
+ ));
+ assertEquals(expectedMethodImpl1, new HashSet<PsiMethod>(Arrays.asList(MethodImplementationsSearch.getMethodImplementations(psiMethod))));
+
+ HashSet<PsiClass> expectedImpls2 = new HashSet<PsiClass>(Arrays.asList(
+ myJavaFacade.findClass("com.test.TestIImpl1", GlobalSearchScope.moduleScope(module2)),
+ myJavaFacade.findClass("com.test.TestIImpl3", GlobalSearchScope.moduleScope(module2))
+ ));
+ assertEquals(expectedImpls2, new HashSet<PsiClass>(getClassImplementations(test2)));
+
+ HashSet<PsiClass> expectedImpls3 = new HashSet<PsiClass>(Arrays.asList(
+ myJavaFacade.findClass("com.test.TestIImpl1", GlobalSearchScope.moduleScope(module3))
+ ));
+ assertEquals(expectedImpls3, new HashSet<PsiClass>(getClassImplementations(test3)));
+
+ }
+
+}
--- /dev/null
+package com.intellij.psi;
+
+import com.intellij.JavaTestUtil;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.roots.*;
+import com.intellij.openapi.roots.libraries.Library;
+import com.intellij.openapi.roots.libraries.LibraryTable;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.testFramework.PsiTestCase;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author dsl
+ */
+public class LibraryOrderTest extends PsiTestCase {
+
+ public void test1() {
+ setupPaths();
+ checkClassFromLib("test.A", "1");
+
+ final ModifiableRootModel rootModel = ModuleRootManager.getInstance(myModule).getModifiableModel();
+ final OrderEntry[] order = rootModel.getOrderEntries();
+ final int length = order.length;
+ OrderEntry lib2 = order[length - 1];
+ OrderEntry lib1 = order[length - 2];
+ assertTrue(lib1 instanceof LibraryOrderEntry);
+ assertEquals("lib1", ((LibraryOrderEntry) lib1).getLibraryName());
+ assertTrue(lib2 instanceof LibraryOrderEntry);
+ assertEquals("lib2", ((LibraryOrderEntry) lib2).getLibraryName());
+
+ order[length - 1] = lib1;
+ order[length - 2] = lib2;
+ rootModel.rearrangeOrderEntries(order);
+
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ rootModel.commit();
+ }
+ }
+ );
+
+ checkClassFromLib("test.A", "2");
+ }
+
+ public void testNavigation() throws Exception {
+ setupPaths();
+ final JavaPsiFacade psiManager = getJavaFacade();
+ final PsiClass classA = psiManager.findClass("test.A");
+ final PsiElement navigationElement = classA.getNavigationElement();
+ assertNotNull(navigationElement);
+ assertTrue(navigationElement != classA);
+ assertEquals("A.java", navigationElement.getContainingFile().getVirtualFile().getName());
+ }
+
+ private void checkClassFromLib(String qualifiedName, String index) {
+ final PsiClass classA = (PsiClass)JavaPsiFacade.getInstance(myProject).findClass(qualifiedName).getNavigationElement();
+ assertNotNull(classA);
+ final PsiMethod[] methodsA = classA.getMethods();
+ assertEquals(1, methodsA.length);
+ assertEquals("methodOfClassFromLib" + index, methodsA[0].getName());
+ }
+
+ public void setupPaths() {
+ final String basePath = JavaTestUtil.getJavaTestDataPath() + "/psi/libraryOrder/";
+
+ final VirtualFile lib1SrcFile = refreshAndFindFile(basePath + "lib1/src");
+ final VirtualFile lib1classes = refreshAndFindFile(basePath + "lib1/classes");
+ final VirtualFile lib2SrcFile = refreshAndFindFile(basePath + "lib2/src");
+ final VirtualFile lib2classes = refreshAndFindFile(basePath + "lib2/classes");
+
+ assertTrue(lib1SrcFile != null);
+ assertTrue(lib2SrcFile != null);
+
+ final ModifiableRootModel rootModel = ModuleRootManager.getInstance(myModule).getModifiableModel();
+ final LibraryTable libraryTable = rootModel.getModuleLibraryTable();
+
+ addLibraryWithSourcePath("lib1", libraryTable, lib1SrcFile, lib1classes);
+ addLibraryWithSourcePath("lib2", libraryTable, lib2SrcFile, lib2classes);
+
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ rootModel.commit();
+ }
+ });
+ final List<VirtualFile> list = Arrays.asList(OrderEnumerator.orderEntries(myModule).getClassesRoots());
+ assertTrue(list.contains(lib1classes));
+ assertTrue(list.contains(lib2classes));
+ }
+
+ private VirtualFile refreshAndFindFile(String path) {
+ final File ioLib1Src = new File(path);
+ final VirtualFile lib1SrcFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(ioLib1Src);
+ return lib1SrcFile;
+ }
+
+ private void addLibraryWithSourcePath(String name, final LibraryTable libraryTable, final VirtualFile libSource,
+ VirtualFile libClasses) {
+ final Library lib = libraryTable.createLibrary(name);
+ final Library.ModifiableModel libModel = lib.getModifiableModel();
+ libModel.addRoot(libClasses, OrderRootType.CLASSES);
+ libModel.addRoot(libSource, OrderRootType.SOURCES);
+ libModel.commit();
+ }
+}
--- /dev/null
+package com.intellij.psi;
+
+import com.intellij.ide.impl.ProjectUtil;
+import com.intellij.mock.MockDocument;
+import com.intellij.mock.MockPsiFile;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.impl.DocumentImpl;
+import com.intellij.openapi.editor.impl.event.DocumentEventImpl;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ex.ProjectManagerEx;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.impl.DebugUtil;
+import com.intellij.psi.impl.PsiDocumentManagerImpl;
+import com.intellij.psi.impl.TextBlock;
+import com.intellij.psi.impl.source.PsiFileImpl;
+import com.intellij.testFramework.LeakHunter;
+import com.intellij.testFramework.LightVirtualFile;
+import com.intellij.testFramework.PlatformTestCase;
+import com.intellij.util.Processor;
+import com.intellij.util.concurrency.Semaphore;
+import com.intellij.util.ui.UIUtil;
+
+import java.io.File;
+import java.lang.ref.Reference;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class PsiDocumentManagerImplTest extends PlatformTestCase {
+ private PsiDocumentManagerImpl getPsiDocumentManager() {
+ return (PsiDocumentManagerImpl)PsiDocumentManager.getInstance(getProject());
+ }
+
+ public void testGetCachedPsiFile_NoFile() throws Exception {
+ final PsiFile file = getPsiDocumentManager().getCachedPsiFile(new MockDocument());
+ assertNull(file);
+ }
+
+ public void testGetPsiFile_NotRegisteredDocument() throws Exception {
+ final PsiFile file = getPsiDocumentManager().getPsiFile(new MockDocument());
+ assertNull(file);
+ }
+
+ public void testGetDocument_FirstGet() throws Exception {
+ VirtualFile vFile = createFile();
+ final PsiFile file = new MockPsiFile(vFile, getPsiManager());
+
+ final Document document = getPsiDocumentManager().getDocument(file);
+ assertNotNull(document);
+ assertSame(document, FileDocumentManager.getInstance().getDocument(vFile));
+ }
+
+ private static LightVirtualFile createFile() {
+ return new LightVirtualFile("foo.java");
+ }
+
+ public void testDocumentGced() throws Exception {
+ VirtualFile vFile = createFile();
+ PsiDocumentManagerImpl documentManager = getPsiDocumentManager();
+ long id = System.identityHashCode(documentManager.getDocument(getPsiManager().findFile(vFile)));
+
+ documentManager.commitAllDocuments();
+ UIUtil.dispatchAllInvocationEvents();
+ UIUtil.dispatchAllInvocationEvents();
+ assertEmpty(documentManager.getUncommittedDocuments());
+
+ LeakHunter.checkLeak(documentManager, DocumentImpl.class);
+ LeakHunter.checkLeak(documentManager, PsiFileImpl.class, new Processor<PsiFileImpl>() {
+ @Override
+ public boolean process(PsiFileImpl psiFile) {
+ return psiFile.getViewProvider().getVirtualFile().getFileSystem() instanceof LocalFileSystem;
+ }
+ });
+ //Class.forName("com.intellij.util.ProfilingUtil").getDeclaredMethod("forceCaptureMemorySnapshot").invoke(null);
+
+ Reference<Document> reference = vFile.getUserData(FileDocumentManagerImpl.DOCUMENT_KEY);
+ assertNotNull(reference);
+ for (int i=0;i<1000;i++) {
+ UIUtil.dispatchAllInvocationEvents();
+ if (reference.get() == null) break;
+ System.gc();
+ }
+ assertNull(documentManager.getCachedDocument(getPsiManager().findFile(vFile)));
+
+ Document newDoc = documentManager.getDocument(getPsiManager().findFile(vFile));
+ assertTrue(id != System.identityHashCode(newDoc));
+ }
+
+ public void testGetUncommittedDocuments_noDocuments() throws Exception {
+ assertEquals(0, getPsiDocumentManager().getUncommittedDocuments().length);
+ }
+
+ public void testGetUncommittedDocuments_documentChanged_DontProcessEvents() throws Exception {
+ PsiFile file = getPsiManager().findFile(createFile());
+
+ final Document document = getPsiDocumentManager().getDocument(file);
+
+ final TextBlock block = TextBlock.get(file);
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ public void run() {
+ block.performAtomically(new Runnable() {
+ @Override
+ public void run() {
+ getPsiDocumentManager().documentChanged(new DocumentEventImpl(document, 0, "", "", document.getModificationStamp(), false));
+ }
+ });
+ }
+ });
+
+
+ assertEquals(0, getPsiDocumentManager().getUncommittedDocuments().length);
+ }
+
+ public void testGetUncommittedDocuments_documentNotRegistered() throws Exception {
+ final Document document = new MockDocument();
+
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ public void run() {
+ getPsiDocumentManager().documentChanged(new DocumentEventImpl(document, 0, "", "", document.getModificationStamp(), false));
+ }
+ });
+
+
+ assertEquals(0, getPsiDocumentManager().getUncommittedDocuments().length);
+ }
+
+ public void testCommitDocument_RemovesFromUncommittedList() throws Exception {
+ PsiFile file = getPsiManager().findFile(createFile());
+
+ final Document document = getPsiDocumentManager().getDocument(file);
+
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ public void run() {
+ getPsiDocumentManager().documentChanged(new DocumentEventImpl(document, 0, "", "", document.getModificationStamp(), false));
+ }
+ });
+
+
+ getPsiDocumentManager().commitDocument(document);
+ assertEquals(0, getPsiDocumentManager().getUncommittedDocuments().length);
+ }
+
+ public void testCommitAllDocument_RemovesFromUncommittedList() throws Exception {
+ PsiFile file = getPsiManager().findFile(createFile());
+
+ final Document document = getPsiDocumentManager().getDocument(file);
+
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ public void run() {
+ getPsiDocumentManager().documentChanged(new DocumentEventImpl(document, 0, "", "", document.getModificationStamp(), false));
+ }
+ });
+
+
+ getPsiDocumentManager().commitAllDocuments();
+ assertEquals(0, getPsiDocumentManager().getUncommittedDocuments().length);
+ }
+
+ public void testDocumentFromAlienProjectDoesNotEndsUpInMyUncommittedList() throws Exception {
+ PsiFile file = getPsiManager().findFile(createFile());
+
+ final Document document = getPsiDocumentManager().getDocument(file);
+
+ File temp = createTempDirectory();
+ final Project alienProject = createProject(new File(temp, "alien.ipr"), DebugUtil.currentStackTrace());
+ boolean succ2 = ProjectManagerEx.getInstanceEx().openProject(alienProject);
+ assertTrue(succ2);
+
+
+ try {
+ PsiManager alienManager = PsiManager.getInstance(alienProject);
+ final String alienText = "alien";
+
+ LightVirtualFile alienVirt = new LightVirtualFile("foo.java", alienText);
+ final PsiFile alienFile = alienManager.findFile(alienVirt);
+ final PsiDocumentManagerImpl alienDocManager = (PsiDocumentManagerImpl)PsiDocumentManager.getInstance(alienProject);
+ final Document alienDocument = alienDocManager.getDocument(alienFile);
+ //alienDocument.putUserData(CACHED_VIEW_PROVIDER, new MockFileViewProvider(alienFile));
+ assertEquals(0, alienDocManager.getUncommittedDocuments().length);
+ assertEquals(0, getPsiDocumentManager().getUncommittedDocuments().length);
+
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ public void run() {
+ getPsiDocumentManager()
+ .documentChanged(new DocumentEventImpl(alienDocument, 0, "", "", alienDocument.getModificationStamp(), false));
+ assertEquals(0, getPsiDocumentManager().getUncommittedDocuments().length);
+ assertEquals(0, alienDocManager.getUncommittedDocuments().length);
+
+ alienDocManager.documentChanged(new DocumentEventImpl(alienDocument, 0, "", "", alienDocument.getModificationStamp(), false));
+ assertEquals(0, getPsiDocumentManager().getUncommittedDocuments().length);
+ assertEquals(1, alienDocManager.getUncommittedDocuments().length);
+
+ getPsiDocumentManager().documentChanged(new DocumentEventImpl(document, 0, "", "", document.getModificationStamp(), false));
+ assertEquals(1, getPsiDocumentManager().getUncommittedDocuments().length);
+ assertEquals(1, alienDocManager.getUncommittedDocuments().length);
+
+ alienDocManager.documentChanged(new DocumentEventImpl(document, 0, "", "", document.getModificationStamp(), false));
+ assertEquals(1, getPsiDocumentManager().getUncommittedDocuments().length);
+ assertEquals(1, alienDocManager.getUncommittedDocuments().length);
+ }
+ });
+ }
+ finally {
+ ProjectUtil.closeAndDispose(alienProject);
+ }
+ }
+
+ public void testCommitInBackground() {
+ PsiFile file = getPsiManager().findFile(createFile());
+ assertTrue(file.isPhysical());
+ final Document document = getPsiDocumentManager().getDocument(file);
+
+ final Semaphore semaphore = new Semaphore();
+ semaphore.down();
+ getPsiDocumentManager().performWhenAllCommitted(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(getPsiDocumentManager().isCommitted(document));
+ semaphore.up();
+ }
+ });
+ waitAndPump(semaphore);
+ assertTrue(getPsiDocumentManager().isCommitted(document));
+
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ public void run() {
+ document.insertString(0, "class X {}");
+ }
+ });
+
+ semaphore.down();
+ getPsiDocumentManager().performWhenAllCommitted(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(getPsiDocumentManager().isCommitted(document));
+ semaphore.up();
+ }
+ });
+ waitAndPump(semaphore);
+ assertTrue(getPsiDocumentManager().isCommitted(document));
+
+ final AtomicInteger count = new AtomicInteger();
+ final Runnable action = new Runnable() {
+ @Override
+ public void run() {
+ count.incrementAndGet();
+ }
+ };
+
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ public void run() {
+ document.insertString(0, "/**/");
+ boolean executed = getPsiDocumentManager().cancelAndRunWhenAllCommitted("xxx", action);
+ assertFalse(executed);
+ executed = getPsiDocumentManager().cancelAndRunWhenAllCommitted("xxx", action);
+ assertFalse(executed);
+ assertEquals(0, count.get());
+ }
+ });
+
+ while (!getPsiDocumentManager().isCommitted(document)) {
+ UIUtil.dispatchAllInvocationEvents();
+ }
+ assertTrue(getPsiDocumentManager().isCommitted(document));
+ assertEquals(1, count.get());
+
+ count.set(0);
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ public void run() {
+ document.insertString(0, "/**/");
+ boolean executed = getPsiDocumentManager().performWhenAllCommitted(action);
+ assertFalse(executed);
+ executed = getPsiDocumentManager().performWhenAllCommitted(action);
+ assertFalse(executed);
+ assertEquals(0, count.get());
+ }
+ });
+
+ while (!getPsiDocumentManager().isCommitted(document)) {
+ UIUtil.dispatchAllInvocationEvents();
+ }
+ assertTrue(getPsiDocumentManager().isCommitted(document));
+ assertEquals(2, count.get());
+ }
+
+ private static void waitAndPump(Semaphore semaphore) {
+ while (!semaphore.waitFor(10)) {
+ UIUtil.dispatchAllInvocationEvents();
+ }
+ }
+
+ @Override
+ protected boolean isRunInWriteAction() {
+ return false;
+ }
+}
--- /dev/null
+package com.intellij.psi;
+
+import com.intellij.ide.highlighter.JavaFileType;
+import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.openapi.editor.SelectionModel;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.util.PsiModificationTracker;
+import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
+import com.intellij.util.Processor;
+import org.jetbrains.annotations.NonNls;
+
+import java.io.IOException;
+
+/**
+ * @author Dmitry Avdeev
+ */
+public class PsiModificationTrackerTest extends LightPlatformCodeInsightFixtureTestCase {
+ public void testAnnotationNotChanged() throws Exception {
+ doReplaceTest("@SuppressWarnings(\"zz\")\n" +
+ "public class Foo { <selection></selection>}",
+ "hi");
+ }
+
+ public void testAnnotationNameChanged() throws Exception {
+ doReplaceTest("@Suppr<selection>ess</selection>Warnings(\"zz\")\n" +
+ "public class Foo { }",
+ "hi");
+ }
+
+ public void testAnnotationParameterChanged() throws Exception {
+ doReplaceTest("@SuppressWarnings(\"<selection>zz</selection>\")\n" +
+ "public class Foo { }",
+ "hi");
+ }
+
+ public void testAnnotationRemoved() throws Exception {
+ doReplaceTest("<selection>@SuppressWarnings(\"zz\")</selection>\n" +
+ "public class Foo { }",
+ "");
+ }
+
+ public void testAnnotationWithClassRemoved() throws Exception {
+ doReplaceTest("<selection>@SuppressWarnings(\"zz\")\n" +
+ "public </selection> class Foo { }",
+ "");
+ }
+
+ public void testRemoveAnnotatedMethod() throws Exception {
+ doReplaceTest("public class Foo {\n" +
+ " <selection> " +
+ " @SuppressWarnings(\"\")\n" +
+ " public void method() {}\n" +
+ "</selection>" +
+ "}",
+ "");
+ }
+
+ public void testRenameAnnotatedMethod() throws Exception {
+ doReplaceTest("public class Foo {\n" +
+ " @SuppressWarnings(\"\")\n" +
+ " public void me<selection>th</selection>od() {}\n" +
+ "}",
+ "zzz");
+ }
+
+ public void testRenameAnnotatedClass() throws Exception {
+ doReplaceTest(" @SuppressWarnings(\"\")\n" +
+ "public class F<selection>o</selection>o {\n" +
+ " public void method() {}\n" +
+ "}",
+ "zzz");
+ }
+
+ public void testRemoveAll() throws Exception {
+ doReplaceTest("<selection>@SuppressWarnings(\"zz\")\n" +
+ "public class Foo { }</selection>",
+ "");
+ }
+
+ public void testRemoveFile() throws Exception {
+ doTest("<selection>@SuppressWarnings(\"zz\")\n" +
+ "public class Foo { }</selection>",
+ new Processor<PsiFile>() {
+ @Override
+ public boolean process(PsiFile psiFile) {
+ try {
+ final VirtualFile vFile = psiFile.getVirtualFile();
+ assert vFile != null : psiFile;
+ vFile.delete(this);
+ }
+ catch (IOException e) {
+ fail(e.getMessage());
+ }
+ return false;
+ }
+ });
+ }
+
+ private void doReplaceTest(@NonNls String text, @NonNls final String with) {
+ doTest(text, new Processor<PsiFile>() {
+ @Override
+ public boolean process(PsiFile psiFile) {
+ replaceSelection(with);
+ return false;
+ }
+ });
+ }
+
+ private void doTest(@NonNls String text, Processor<PsiFile> run) {
+ PsiFile file = myFixture.configureByText(JavaFileType.INSTANCE, text);
+ PsiModificationTracker modificationTracker = PsiManager.getInstance(getProject()).getModificationTracker();
+ long count = modificationTracker.getModificationCount();
+ run.process(file);
+ assertFalse(modificationTracker.getModificationCount() == count);
+ }
+
+ private void replaceSelection(final String with) {
+ new WriteCommandAction.Simple(getProject()) {
+ @Override
+ protected void run() throws Throwable {
+ SelectionModel sel = myFixture.getEditor().getSelectionModel();
+ myFixture.getEditor().getDocument().replaceString(sel.getSelectionStart(), sel.getSelectionEnd(), with);
+ PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
+ }
+ }.execute();
+ }
+
+ public void testJavaStructureModificationChangesAfterPackageDelete() {
+ PsiFile file = myFixture.addFileToProject("/x/y/Z.java", "text");
+ PsiModificationTracker modificationTracker = PsiManager.getInstance(getProject()).getModificationTracker();
+ long count = modificationTracker.getJavaStructureModificationCount();
+
+ file.getContainingDirectory().delete();
+
+ assertEquals(count + 1, modificationTracker.getJavaStructureModificationCount());
+ }
+}
--- /dev/null
+package com.intellij.psi;
+
+import com.intellij.JavaTestUtil;
+import com.intellij.codeInsight.CodeInsightTestCase;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.EditorFactory;
+import com.intellij.openapi.editor.event.DocumentEvent;
+import com.intellij.openapi.editor.event.DocumentListener;
+import com.intellij.openapi.editor.event.EditorEventMulticaster;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.openapi.projectRoots.impl.JavaSdkImpl;
+import com.intellij.openapi.vfs.VfsUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.impl.source.PsiFileImpl;
+import com.intellij.psi.impl.source.tree.FileElement;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.stubs.StubTree;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
+import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.testFramework.PlatformTestCase;
+import com.intellij.testFramework.PsiTestUtil;
+import com.intellij.util.FileContentUtil;
+import gnu.trove.THashSet;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Set;
+
+@PlatformTestCase.WrapInCommand
+public class SmartPsiElementPointersTest extends CodeInsightTestCase {
+ private VirtualFile myRoot;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ String root = JavaTestUtil.getJavaTestDataPath() + "/codeEditor/smartPsiElementPointers";
+ PsiTestUtil.removeAllRoots(myModule, JavaSdkImpl.getMockJdk17());
+ myRoot = PsiTestUtil.createTestProjectStructure(myProject, myModule, root, myFilesToDelete);
+ }
+
+ public void testChangeInDocument() {
+ PsiClass aClass = myJavaFacade.findClass("AClass", GlobalSearchScope.allScope(getProject()));
+ assertNotNull(aClass);
+
+ SmartPsiElementPointer pointer = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass);
+ Document document = PsiDocumentManager.getInstance(myProject).getDocument(aClass.getContainingFile());
+
+ int offset = aClass.getTextOffset();
+ document.insertString(offset, "/**/");
+ PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+
+ PsiElement element = pointer.getElement();
+ assertNotNull(element);
+ assertTrue(element instanceof PsiClass);
+ assertTrue(element.isValid());
+ }
+
+ // This test is unfair. If pointer would be asked for getElement() between commits it'll never restore again anyway.
+ //
+ public void testChangeInDocumentTwice() {
+ PsiClass aClass = myJavaFacade.findClass("AClass",GlobalSearchScope.allScope(getProject()));
+ assertNotNull(aClass);
+
+ SmartPsiElementPointer pointer = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass);
+ Document document = PsiDocumentManager.getInstance(myProject).getDocument(aClass.getContainingFile());
+
+ int offset = aClass.getTextOffset();
+ document.insertString(offset, "/*");
+ PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+ document.insertString(offset + 2, "*/");
+ PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+
+ PsiElement element = pointer.getElement();
+ assertNotNull(element);
+ assertTrue(element instanceof PsiClass);
+ assertTrue(element.isValid());
+ }
+
+ public void testGetElementWhenDocumentModified() {
+ PsiClass aClass = myJavaFacade.findClass("AClass",GlobalSearchScope.allScope(getProject()));
+ assertNotNull(aClass);
+
+ SmartPsiElementPointer pointer = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass);
+ Document document = PsiDocumentManager.getInstance(myProject).getDocument(aClass.getContainingFile());
+
+ int offset = aClass.getTextOffset();
+ document.insertString(offset, "/**/");
+ PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+
+ document.insertString(offset, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ PsiElement element = pointer.getElement();
+ assertNotNull(element);
+ assertTrue(element instanceof PsiClass);
+ assertTrue(element.isValid());
+ }
+
+ public void testKeepBeltWhenDocumentModified() {
+ PsiClass aClass = myJavaFacade.findClass("AClass",GlobalSearchScope.allScope(getProject()));
+ assertNotNull(aClass);
+
+ SmartPsiElementPointer pointer = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass);
+ Document document = PsiDocumentManager.getInstance(myProject).getDocument(aClass.getContainingFile());
+
+ int offset = aClass.getTextOffset();
+ document.insertString(offset, "/******/");
+
+ pointer.getElement();
+
+ document.insertString(offset, "/**/");
+ PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+
+ PsiElement element = pointer.getElement();
+ assertNotNull(element);
+ assertTrue(element instanceof PsiClass);
+ assertTrue(element.isValid());
+ }
+
+ public void testChangeInPsi() {
+ PsiClass aClass = myJavaFacade.findClass("AClass",GlobalSearchScope.allScope(getProject()));
+ assertNotNull(aClass);
+
+ SmartPsiElementPointer pointer = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass);
+ Document document = PsiDocumentManager.getInstance(myProject).getDocument(aClass.getContainingFile());
+
+ int offset = aClass.getTextOffset();
+ document.insertString(offset, "/**/");
+ PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+
+ PsiElement element = pointer.getElement();
+ assertNotNull(element);
+ assertTrue(element instanceof PsiClass);
+ assertTrue(element.isValid());
+ }
+
+ public void testPsiChangesWithLazyPointers() throws Exception {
+ PsiClass aClass = myJavaFacade.findClass("AClass",GlobalSearchScope.allScope(getProject()));
+ assertNotNull(aClass);
+
+ final SmartPsiElementPointer<PsiIdentifier> pointer = SmartPointerManager.getInstance(myProject).createLazyPointer(aClass.getNameIdentifier());
+ final PsiComment javadoc =
+ JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createCommentFromText("/** javadoc */", aClass);
+ aClass.getParent().addBefore(javadoc, aClass);
+
+ final PsiIdentifier elt = pointer.getElement();
+ assertNotNull(elt);
+ assertSame(elt, aClass.getNameIdentifier());
+ }
+
+ public void testTypePointer() {
+ PsiClass aClass = myJavaFacade.findClass("AClass",GlobalSearchScope.allScope(getProject()));
+ final PsiTypeElement typeElement = myJavaFacade.findClass("Test",GlobalSearchScope.allScope(getProject())).getFields()[0].getTypeElement();
+
+ SmartPsiElementPointer typePointer = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(typeElement);
+ SmartPsiElementPointer classPointer = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass);
+
+ Document aClassDocument = PsiDocumentManager.getInstance(myProject).getDocument(aClass.getContainingFile());
+ Document testDocument = PsiDocumentManager.getInstance(myProject).getDocument(typeElement.getContainingFile());
+
+ aClassDocument.insertString(aClass.getTextOffset(), "/**/");
+ testDocument.insertString(typeElement.getTextOffset(), "/**/");
+ PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+
+ PsiElement element = typePointer.getElement();
+ assertNotNull(element);
+ assertTrue(element instanceof PsiTypeElement);
+ assertTrue(element.isValid());
+ assertEquals(classPointer.getElement(), PsiUtil.resolveClassInType(((PsiTypeElement)element).getType()));
+ }
+
+ public void testCreatePointerInBeforeDocumentChange() {
+ final PsiClass aClass = myJavaFacade.findClass("AClass",GlobalSearchScope.allScope(getProject()));
+ assertNotNull(aClass);
+
+ Document document = PsiDocumentManager.getInstance(myProject).getDocument(aClass.getContainingFile());
+
+ final SmartPsiElementPointer[] pointer = new SmartPsiElementPointer[1];
+ int offset = aClass.getTextOffset();
+ DocumentListener listener = new DocumentListener() {
+ @Override
+ public void beforeDocumentChange(DocumentEvent event) {
+ pointer[0] = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass);
+ }
+
+ @Override
+ public void documentChanged(DocumentEvent event) {
+ }
+ };
+ EditorEventMulticaster multicaster = EditorFactory.getInstance().getEventMulticaster();
+ multicaster.addDocumentListener(listener);
+ try {
+ document.insertString(offset, "/******/");
+ }
+ finally {
+ multicaster.removeDocumentListener(listener);
+ }
+
+ pointer[0].getElement();
+
+ document.insertString(0, "/**/");
+ PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+
+ PsiElement element = pointer[0].getElement();
+ assertNotNull(element);
+ assertTrue(element instanceof PsiClass);
+ assertTrue(element.isValid());
+ }
+
+ public void testCreatePointerWhenNoPsiFile() {
+ myPsiManager.startBatchFilesProcessingMode(); // to use weak refs
+
+ try {
+ final PsiClass aClass = myJavaFacade.findClass("AClass",GlobalSearchScope.allScope(getProject()));
+ assertNotNull(aClass);
+
+ VirtualFile vFile = myRoot.findChild("AClass.java");
+ assertNotNull(vFile);
+ PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(myProject);
+ Document document = FileDocumentManager.getInstance().getDocument(vFile);
+
+ final SmartPsiElementPointer pointer = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass);
+
+ System.gc();
+ /*
+ PsiFile psiFile = myPsiManager.getFileManager().getCachedPsiFile(vFile);
+ assertNull(psiFile);
+ */
+
+ document.insertString(0, "class Foo{}\n");
+
+ PsiElement element = pointer.getElement();
+ assertEquals(aClass, element);
+
+ document.insertString(0, "/**/");
+ psiDocumentManager.commitAllDocuments();
+
+ if (aClass.isValid()) {
+ aClass.getChildren();
+ }
+
+ element = pointer.getElement();
+ assertNotNull(element);
+ assertTrue(element instanceof PsiClass);
+ assertTrue(element.isValid());
+ }
+ finally {
+ myPsiManager.finishBatchFilesProcessingMode(); // to use weak refs
+ }
+ }
+
+ public void testReplaceFile() throws IOException {
+ VirtualFile vfile = myRoot.createChildData(this, "X.java");
+ VfsUtil.saveText(vfile, "public class X { public int X; }");
+
+ PsiClass aClass = myJavaFacade.findClass("X", GlobalSearchScope.allScope(getProject()));
+ assertNotNull(aClass);
+ assertTrue(aClass.isValid());
+
+ SmartPsiElementPointer classp = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass);
+ SmartPsiElementPointer filep = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass.getContainingFile());
+
+ FileContentUtil.reparseFiles(myProject, Collections.<VirtualFile>singleton(vfile), true);
+ PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+ assertFalse(aClass.isValid());
+
+ PsiElement element = classp.getElement();
+ assertNotNull(element);
+ assertTrue(element instanceof PsiClass);
+ assertTrue(element.isValid());
+ assertEquals(vfile, element.getContainingFile().getVirtualFile());
+
+ element = filep.getElement();
+ assertNotNull(element);
+ assertTrue(element instanceof PsiFile);
+ assertTrue(element.isValid());
+ assertEquals(vfile, element.getContainingFile().getVirtualFile());
+ }
+
+ public void testCreatePointerDoesNotLoadPsiTree() throws IOException {
+ VirtualFile vfile = myRoot.createChildData(this, "X.java");
+ VfsUtil.saveText(vfile, "public class X { public int X; }");
+
+ PsiClass aClass = myJavaFacade.findClass("X", GlobalSearchScope.allScope(getProject()));
+ assertNotNull(aClass);
+ assertTrue(aClass.isValid());
+
+ PsiFileImpl file = (PsiFileImpl)aClass.getContainingFile();
+
+ assertTreeLoaded(file, false);
+
+ SmartPsiElementPointer p = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass);
+ assertNotNull(p);
+
+ assertTreeLoaded(file, false);
+
+ assertInstanceOf(p.getElement(), PsiClass.class);
+
+ assertTreeLoaded(file, false);
+
+ PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject);
+ Document document = documentManager.getDocument(file);
+ document.insertString(0, "/** asdasd */");
+ documentManager.commitAllDocuments();
+
+ // loaded tree
+ assertTreeLoaded(file, true);
+
+ assertInstanceOf(p.getElement(), PsiClass.class);
+
+ assertTreeLoaded(file, true);
+ }
+
+ private static void assertTreeLoaded(PsiFileImpl file, boolean loaded) {
+ FileElement treeElement = file.getTreeElement();
+ assertEquals(loaded, treeElement != null);
+ StubTree stubTree = file.getStubTree();
+ assertEquals(loaded, stubTree == null);
+ }
+
+ public void testPointerDisambiguationAfterDupLine() throws Exception {
+ PsiJavaFile file = (PsiJavaFile)configureByText(StdFileTypes.JAVA, "class XXX{ void foo() { \n" +
+ " <caret>foo();\n" +
+ "}}");
+ PsiClass aClass = file.getClasses()[0];
+ assertNotNull(aClass);
+
+ PsiReferenceExpression ref1 = PsiTreeUtil.getParentOfType(PsiUtilBase.getElementAtCaret(getEditor()), PsiReferenceExpression.class);
+ SmartPsiElementPointer pointer1 = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(ref1);
+
+ ctrlD();
+ PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+
+ Set<PsiReferenceExpression> refs = new THashSet<PsiReferenceExpression>();
+ int offset=0;
+ while (true) {
+ offset = getEditor().getDocument().getText().indexOf("foo();", offset+1);
+ if (offset == -1) break;
+ PsiReferenceExpression ref2 = PsiTreeUtil.getParentOfType(getFile().findElementAt(offset), PsiReferenceExpression.class);
+ refs.add(ref2);
+ }
+ refs.remove(ref1);
+ assertEquals(1, refs.size());
+ PsiReferenceExpression ref2 = refs.iterator().next();
+ assertNotSame(ref1, ref2);
+ SmartPsiElementPointer pointer2 = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(ref2);
+ assertNotSame(pointer1, pointer2);
+
+ PsiElement element1 = pointer1.getElement();
+ PsiElement element2 = pointer2.getElement();
+
+ assertNotNull(element1);
+ assertNotNull(element2);
+ assertNotSame(element1, element2);
+
+ assertFalse(SmartPointerManager.getInstance(myProject).pointToTheSameElement(pointer1, pointer2));
+ }
+}
--- /dev/null
+/*
+ * @author max
+ */
+package com.intellij.psi;
+
+import com.intellij.openapi.editor.Document;
+import com.intellij.psi.impl.DebugUtil;
+import com.intellij.testFramework.LightCodeInsightTestCase;
+
+public class TreeIsCorrectAfterDiffReparseTest extends LightCodeInsightTestCase {
+
+ public void testIDEADEV41862() throws Exception {
+ String part1 = "package com.test;\n" +
+ "\n" +
+ "\n" +
+ "//------------------------------------------------------------------\n" +
+ "// Copyright (c) 1999, 2007\n" +
+ "// WorkForce Software, Inc.\n" +
+ "// All rights reserved.\n" +
+ "//\n" +
+ "// Web-site: http://www.workforcesoftware.com\n" +
+ "// E-mail: support@workforcesoftware.com\n" +
+ "// Phone: (877) 493-6723\n" +
+ "//\n" +
+ "// This program is protected by copyright laws and is considered\n" +
+ "// a trade secret of WorkForce Software. Access to this program\n" +
+ "// and source code is granted only to licensed customers. Under\n" +
+ "// no circumstances may this software or source code be distributed\n" +
+ "// without the prior written consent of WorkForce Software.\n" +
+ "// -----------------------------------------------------------------\n" +
+ "\n" +
+ "import com.workforcesoftware.Data.Employee.*;\n" +
+ "import com.workforcesoftware.Data.*;\n" +
+ "import com.workforcesoftware.Data.assignment.Asgnmt_master;\n" +
+ "import com.workforcesoftware.Data.assignment.Asgnmt;\n" +
+ "import com.workforcesoftware.Data.Output.Time_sheet_output;\n" +
+ "import com.workforcesoftware.Data.TimeSched.PayPeriodData;\n" +
+ "import com.workforcesoftware.Data.TimeSched.TimeSchedUtils;\n" +
+ "import com.workforcesoftware.Data.TimeSched.Schedule.Schedule_detailList;\n" +
+ "import com.workforcesoftware.Data.TimeSched.TimeSheet.*;\n" +
+ "import com.workforcesoftware.Data.assignment.Asgnmt_masterList;\n" +
+ "import com.workforcesoftware.Exceptions.*;\n" +
+ "import com.workforcesoftware.Gen.Choice.Approval_event_type;\n" +
+ "import com.workforcesoftware.Gen.Choice.Transaction_status;\n" +
+ "import com.workforcesoftware.Gen.Choice.Messages;\n" +
+ "import com.workforcesoftware.Gen.Choice.Program_source;\n" +
+ "import com.workforcesoftware.Gen.Other.DbRec.DbRecTime_sheet_output;\n" +
+ "import com.workforcesoftware.Gen.Other.DbRec.DbRecTime_sheet;\n" +
+ "import com.workforcesoftware.Gen.Other.List.WDateList;\n" +
+ "import com.workforcesoftware.Gen.Policy.Right_grp;\n" +
+ "import com.workforcesoftware.Gen.Policy.Policy_profile;\n" +
+ "import com.workforcesoftware.Policy.*;\n" +
+ "import com.workforcesoftware.Util.DateTime.WDate;\n" +
+ "import com.workforcesoftware.Util.DateTime.WDateTime;\n" +
+ "import com.workforcesoftware.Util.DB.ListWriter;\n" +
+ "import com.workforcesoftware.Util.DB.DbRecFieldCopier;\n" +
+ "import com.workforcesoftware.ClientRequests.TimeSched.TimeSchedUtil;\n" +
+ "import com.workforcesoftware.ClientRequests.TimeSched.PayPeriodInfo;\n" +
+ "import com.workforcesoftware.ClientRequests.TimeEntry.ApprovalInfo;\n" +
+ "import com.workforcesoftware.ClientRequests.TimeEntry.BankBalanceResults;\n" +
+ "import com.workforcesoftware.Misc.ServerErrorLogger;\n" +
+ "import com.workforcesoftware.Misc.ServerError;\n" +
+ "import com.workforcesoftware.AssignmentPeriod.*;\n" +
+ "import com.workforcesoftware.AssignmentPeriod.TimeSheetState;\n" +
+ "import com.workforcesoftware.Dictionary.DataDictionary;\n" +
+ "\n" +
+ "import java.sql.SQLException;\n" +
+ "import java.util.*;\n" +
+ "import org.log4j.Category;\n" +
+ "\n" +
+ "/**\n" +
+ " * Holds definition of {@link CalcInfo}\n" +
+ " */\n" +
+ "class AssignmentManager {\n" +
+ " /**\n" +
+ " * Implementation of {@link TimeSheetCalculationInfo}.\n" +
+ " * Extracts all the required data from AllCalcDataManager, AllCalculationData, Time_sheet, etc.\n" +
+ " * Makes copies of all mutable data, unmodifiable lists where possible.\n" +
+ " */\n" +
+ " static class CalcInfo implements TimeSheetCalculationInfo {\n" +
+ " /**\n" +
+ " * Use the passed in AllCalculationData object - DO NOT try to get it from the passed in AllCalcDataManager because\n" +
+ " * the ACD object that's passed in is obtained from AssignmentManager.getAllCalcData method which handles the\n" +
+ " * scenario where a prior period may need to be amended automatically and if ACDM.getAllCalcData() method is called,\n" +
+ " * you might get an unmodifiable ACD\n" +
+ " * @param acdm\n" +
+ " * @param acd\n" +
+ " * @param timeSheetId\n" +
+ " * @param parms\n" +
+ " */\n" +
+ " CalcInfo(AllCalcDataManager acdm, AllCalculationData acd, TimeSheetIdentifier timeSheetId, TimeEntryParms parms) {\n" +
+ " // we'll extract all these vars separately, for readability\n" +
+ " final Right_grp rightGrp = parms.getRight_grp(timeSheetId);\n" +
+ " final AllPolicies ap = acd.getAllPolicies();\n" +
+ " final WDate ppEndForToday = TimeSchedUtil.getPayPeriodRangeForToday(acdm).getEnd();\n" +
+ "\n" +
+ " this.acd = acd;\n" +
+ " this.timeSheetIdentifier = timeSheetId;\n" +
+ " this.approval_eventList = acd.getApproval_eventList().getUnmodifiableList();\n" +
+ " this.policyProfile = acd.getAsgnmtMaster().getPolicyProfilePolicy(ppEndForToday, ap);\n" +
+ " this.adjustmentsPaidWithTimesheet = createAdjustmentsPaidWithTimesheet(acdm, acd);\n" +
+ " this.bankBalanceResults = acdm.getBankDataForBankBalancePreview(ap, acd, rightGrp.getRight_grp(), acd.getPP_end());\n" +
+ " this.tsoListForPayPreview = Collections.unmodifiableList(acdm.getTsoListForPayPreview(acd, rightGrp.getRight_grp()));\n" +
+ " this.approvedDays = createApprovedDays(acd);\n" +
+ "\n" +
+ " try {\n" +
+ " // these are fairly involved calculations, and we want to validate the pay period list,\n" +
+ " // so we'll do them both here together instead of upon request\n" +
+ " employeePeriodInfo = acdm.getEmployeePeriodInfo(timeSheetId.getPpEnd());\n" +
+ " payPeriodList = TimeSchedUtil.calcPayPeriodList(acdm, rightGrp.getRight_grp());\n" +
+ " }\n" +
+ " catch (Exception e) {\n" +
+ " throw new InternalApplicationException(\"Loading calc data for: \" + timeSheetId, e);\n" +
+ " }\n" +
+ " assertPayPeriodList();\n" +
+ "\n" +
+ " AssignmentPeriodStateImpl aps = new AssignmentPeriodStateImpl(employeePeriodInfo,\n" +
+ " rightGrp, parms.getSystemFeature(), ap, ppEndForToday, acdm, policyProfile);\n" +
+ " assignmentPeriodState = aps;\n" +
+ " timeSheetState = new TimeSheetStateImpl(this, aps, policyProfile);\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Returns an ApprovalInfo object, which contains information about whether\n" +
+ " * employee/manager approved a timesheet.\n" +
+ " *\n" +
+ " * @see ApprovalInfo\n" +
+ " */\n" +
+ " public ApprovalInfo getApprovalInfo() { return new ApprovalInfo(acd.getTime_sheet(), approval_eventList); }\n" +
+ "\n" +
+ " public Collection<DbRecTime_sheet_output> getAdjustmentsPaidWithTimesheet() {\n" +
+ " return adjustmentsPaidWithTimesheet;\n" +
+ " }\n" +
+ "\n" +
+ " public Approval_eventList getApproval_eventList() {\n" +
+ " return approval_eventList;\n" +
+ " }\n" +
+ "\n" +
+ "\n" +
+ " /**\n" +
+ " * Returns state information about a given assignment and period, encompassing\n" +
+ " * the cross-section of security related settings calculated from:\n" +
+ " * <ul>\n" +
+ " * <li>App_user Roles (app_user_right and right_grp tables)\n" +
+ " * <li>Assignment effective dates\n" +
+ " * <li>Employee record effective dates\n" +
+ " * <li>System_feature read/write privileges\n" +
+ " * </ul>\n" +
+ " *\n" +
+ " * @return not ever null\n" +
+ " */\n" +
+ " public AssignmentPeriodState getAssignmentPeriodState() {\n" +
+ " return assignmentPeriodState;\n" +
+ " }\n" +
+ "\n" +
+ " public Set<WDate> getDailyApprovalDays() {\n" +
+ " return approvedDays;\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Returns map to the accrual banks data, which is a read only reference\n" +
+ " * of the information contained there. The banks returned will be all banks attached\n" +
+ " * to the assignment, including aggregate banks if applicable.\n" +
+ " *\n" +
+ " * The list will not contain any banks that the current App_user's Right_grp cannot view for this assignment's\n" +
+ " * Policy_profile (as defined by {@link com.workforcesoftware.Gen.Policy.User_entry_rule_detail#getDisplay_bank_set()})\n" +
+ " */\n" +
+ " public List<BankBalanceResults> getBankBalanceResults() {\n" +
+ " return bankBalanceResults;\n" +
+ " }\n" +
+ "\n" +
+ " public Approval_event getLastValidEmployeeApproveEvent() {\n" +
+ " return approval_eventList.getLastValidEmployeeApproveEvent();\n" +
+ " }\n" +
+ "\n" +
+ " public Time_sheet_detail_splitList getTime_sheet_detail_splitList() {\n" +
+ " return acd.getTime_sheet().getTime_sheet_detail_splitList().getUnmodifiableList();\n" +
+ " }\n" +
+ "\n" +
+ " public Time_sheet_detailList getTime_sheet_detailList() {\n" +
+ " return acd.getTime_sheet().getDetailList().getUnmodifiableList();\n" +
+ " }\n" +
+ "\n" +
+ " public Schedule_detailList getSchedule_detailList() {\n" +
+ " return acd.getSchedule().getDetailList().getUnmodifiableList();\n" +
+ " }\n" +
+ "\n" +
+ " public Time_sheet_exceptionList getTime_sheet_exceptionList() {\n" +
+ " return acd.getTime_sheet().getTime_sheet_exceptionList().getUnmodifiableList();\n" +
+ " }\n" +
+ "\n" +
+ " public List<Time_sheet_output> getTsoListForPayPreview() {\n" +
+ " return tsoListForPayPreview;\n" +
+ " }\n" +
+ "\n" +
+ " public Approval_eventList getValidManagerApproveEvents() {\n" +
+ " return approval_eventList.getValidManagerApproveEvents();\n" +
+ " }\n" +
+ "\n" +
+ " public TimeSheetIdentifier getTimeSheetIdentifier() {\n" +
+ " return timeSheetIdentifier;\n" +
+ " }\n" +
+ "\n" +
+ " public EmployeePeriodInfo getEmployeePeriodInfo() {\n" +
+ " return employeePeriodInfo;\n" +
+ " }\n" +
+ "\n" +
+ " public Employee_master getEmployeeMaster() {\n" +
+ " return new Employee_master(acd.getEmployee_master());\n" +
+ " }\n" +
+ "\n" +
+ " public Employee getEmployee() {\n" +
+ " return new Employee(acd.getEmployee_master().getEmployeeAsOfOrAfter(getPPEnd()));\n" +
+ " }\n" +
+ "\n" +
+ " public Asgnmt_master getAsgnmtMaster() {\n" +
+ " return new Asgnmt_master(acd.getAsgnmtMaster());\n" +
+ " }\n" +
+ "\n" +
+ " public Asgnmt getAsgnmt() {\n" +
+ " return new Asgnmt(acd.getAsgnmt());\n" +
+ " }\n" +
+ "\n" +
+ " public WDate getPPEnd() {\n" +
+ " return employeePeriodInfo.getPp_end();\n" +
+ " }\n" +
+ "\n" +
+ " public WDate getPPBegin() {\n" +
+ " return employeePeriodInfo.getPp_begin();\n" +
+ " }\n" +
+ "\n" +
+ " public Policy_profile getPolicy_profile() {\n" +
+ " return policyProfile;\n" +
+ " }\n" +
+ "\n" +
+ "\n" +
+ " /**\n" +
+ " * Return state information about the timesheet, which considers security\n" +
+ " * relationship between the current state (locked/closed/amended) in relation to:\n" +
+ " * <ul>\n" +
+ " * <li>App_user Roles (app_user_right and right_grp tables)\n" +
+ " * <li>Assignment effective dates\n" +
+ " * <li>Employee record effective dates\n" +
+ " * <li>System_feature read/write privileges\n" +
+ " * <li>Approval level of the timesheet\n" +
+ " * </ul>\n" +
+ " *\n" +
+ " * @return not ever null\n" +
+ " */\n" +
+ " public TimeSheetState getTimeSheetState() {\n" +
+ " return timeSheetState;\n" +
+ " }\n" +
+ "\n" +
+ " public int getVersionNumber() {\n" +
+ " return timeSheetIdentifier.getVersion();\n" +
+ " }\n" +
+ "\n" +
+ " public PayPeriodData getPayPeriodData() {\n" +
+ " return acd.getPayPeriodData();\n" +
+ " }\n" +
+ "\n" +
+ " public boolean getIsNewlyUserAmended() {\n" +
+ " return acd.isNewlyUserAmended();\n" +
+ " }\n" +
+ "\n" +
+ " public List<PayPeriodInfo> getPayPeriodList() {\n" +
+ " return payPeriodList;\n" +
+ " }\n" +
+ "\n" +
+ " private static Collection<DbRecTime_sheet_output> createAdjustmentsPaidWithTimesheet(AllCalcDataManager acdm, AllCalculationData acd) {\n" +
+ " try { return Collections.unmodifiableCollection(acdm.getAdjustmentsPaidWithTimesheet(acd)); }\n" +
+ " catch (SQLException e) { throw new InternalApplicationException(\"Unexpected SQL Exception\", e); }\n" +
+ " }\n" +
+ "\n" +
+ " private void assertPayPeriodList() {\n" +
+ " //TODO - probably need to show a \"nice\" message to the user saying that the employee doesn't\n" +
+ " //TODO - have a viewable/editable pay period.\n" +
+ " if(payPeriodList.isEmpty()) {\n" +
+ " throw new InternalApplicationException(\"No viewable/editable pay periods found for employee \"\n" +
+ " + employeePeriodInfo.getEmployeeMaster().getEmployee());\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " private static Set<WDate> createApprovedDays(AllCalculationData acd) {\n" +
+ " // calculate days approved by daily approvals\n" +
+ " Set<WDate> approvedDays = new HashSet<WDate>();\n" +
+ " for( WDate date : acd.getPayPeriodData().getActiveDates().getAllDates() ) {\n" +
+ " if( acd.isDayApproved(date) ) { approvedDays.add(date); }\n" +
+ " }\n" +
+ " return Collections.unmodifiableSet(approvedDays);\n" +
+ " }\n" +
+ "\n" +
+ " private final Collection<DbRecTime_sheet_output> adjustmentsPaidWithTimesheet;\n" +
+ " private final Approval_eventList approval_eventList;\n" +
+ " private final AssignmentPeriodState assignmentPeriodState;\n" +
+ " private final List<BankBalanceResults> bankBalanceResults;\n" +
+ " private final List<Time_sheet_output> tsoListForPayPreview;\n" +
+ " private final TimeSheetIdentifier timeSheetIdentifier;\n" +
+ " private final TimeSheetState timeSheetState;\n" +
+ " private final EmployeePeriodInfo employeePeriodInfo;\n" +
+ " private final ArrayList<PayPeriodInfo> payPeriodList;\n" +
+ " private final Set<WDate> approvedDays;\n" +
+ " private final Policy_profile policyProfile;\n" +
+ " private final AllCalculationData acd;\n" +
+ " }\n" +
+ "\n" +
+ " AssignmentManager(GeneratedId assignmentId, Set<TimeSheetIdentifier> timeSheetIdentifiers, TimeEntryParmsPerAssignment parms) {\n" +
+ " this.asgnmtMaster = getAggregateOrSingleAssignmentMaster(assignmentId);\n" +
+ " setClassFields(parms, timeSheetIdentifiers);\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Obtains the single or aggregate assignment master for the given assignmentId. If the given assignmentId is not a\n" +
+ " * single or aggregate assignment, fetches the aggregate associated with the given assignmentId and returns that.\n" +
+ " *\n" +
+ " * @param assignmentId Id of the assigment to load.\n" +
+ " * @return the single or aggregate assignment master for the given assignmentId.\n" +
+ " */\n" +
+ " private static Asgnmt_master getAggregateOrSingleAssignmentMaster(GeneratedId assignmentId) {\n" +
+ " Asgnmt_master am = Asgnmt_master.load(assignmentId);\n" +
+ " if(am.isAggregate() || am.isSingle()) {\n" +
+ " return am;\n" +
+ " }\n" +
+ "\n" +
+ " //If it's not a single or aggregate, we need to load the aggregate and load that.\n" +
+ " return Asgnmt_master.load(am.getAggregate_asgnmt());\n" +
+ " }\n" +
+ "\n" +
+ " AggregateTimeEntryTransactionResults load() {\n" +
+ " return loadImpl();\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Reverts any changes that have not been committed to the database on this AssignmentManager\n" +
+ " */\n" +
+ " void revert() {\n" +
+ " updatedAllCalcDataManager = null;\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * @return Return initial transaction results from originalAllCalcData, which must be set before calling this.\n" +
+ " */\n" +
+ " private AggregateTimeEntryTransactionResults loadImpl() {\n" +
+ " AggregateTimeEntryTransactionResults aggregateResults = (AggregateTimeEntryTransactionResults) parms.getTimeEntryResultsFactory().newInstance();\n" +
+ " for (TimeSheetIdentifier timeSheetId : getTimeSheetIdentifiers()) {\n" +
+ " AllCalculationData acd = getOriginalAllCalcData(timeSheetId);\n" +
+ " // Make sure system_record_id's are assigned - TimeEntryManager and client do not function correctly without\n" +
+ " assignSystemRecordIds(acd);\n" +
+ " CalcInfo calcInfo = new CalcInfo(getOriginalAllCalcDataManager(timeSheetId.getAsgnmt()), acd, timeSheetId, parms);\n" +
+ " //todo-ute-nazim do we really need to perform TimeSheetDiff for the initial load ?\n" +
+ " TimeEntryTransactionResults singleTimeSheetResults =\n" +
+ " new TimeSheetDiff(timeSheetId, acd, calcInfo, TimeSheetCounters.getEmptyCounters(), NewToOldIdMap.EMPTY,\n" +
+ " Collections.EMPTY_LIST, new StatusMapsForTimesheetAndSchedule(), true, parms, null);\n" +
+ " aggregateResults.add(singleTimeSheetResults);\n" +
+ " }\n" +
+ " return aggregateResults;\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Assign system_record_id's for time_sheet, time_sheet_detail's and time_sheet_exception's\n" +
+ " * @param acd\n" +
+ " */\n" +
+ " private void assignSystemRecordIds(AllCalculationData acd) {\n" +
+ " assignSystemRecordId(acd.getTime_sheet());\n" +
+ " assignSystemRecordIds(acd.getTime_sheet().getTime_sheet_detailList());\n" +
+ " assignSystemRecordIds(acd.getTime_sheet().getTime_sheet_exceptionList());\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * todo: store the event.getComment()\n" +
+ " * @param event\n" +
+ " */\n" +
+ " AggregateTimeEntryTransactionResults amend(TransactionApprovalEvent event) {\n" +
+ " TimeSheetIdentifier singleTimeSheetId = event.getTimeSheetIdentifier();\n" +
+ " //TODO: Shouldn't this call createOriginalAllCalcDataManagerIfNeeded? Seems like we needlessly reload the original\n" +
+ " //TODO: ACDM. This is because a timesheet which was prepared for amendment couldn't have been modified before it\n" +
+ " //TODO: was amended.\n" +
+ " invalidateAllCalcDataManagers();\n" +
+ "\n" +
+ " // Create the amended ACD and put into the ACDM cache\n" +
+ " EmployeePeriodInfo epInfo = null;\n" +
+ " try {\n" +
+ " AllCalcDataManager acdm = getOriginalAllCalcDataManager(singleTimeSheetId.getAsgnmt());\n" +
+ " epInfo = acdm.getEmployeePeriodInfo(singleTimeSheetId.getPpEnd());\n" +
+ " AllCalculationData amendedAllCalcData = acdm.createAmendedAllCalcData(epInfo, parms.getApp_user(), WDateTime.now());\n" +
+ " // No need to hook this up to approval change logic, since it is an in-memory change so far.\n" +
+ " //Recalculate the amended ACD object so that timesheet exceptions that are on the closed version (if any)\n" +
+ " // get created on the amended timesheet as well\n" +
+ " amendedAllCalcData.recalc(acdm);\n" +
+ " }\n" +
+ " catch (SQLException e) {\n" +
+ " throw new InternalApplicationException(\"amending time sheet for \" + singleTimeSheetId, e);\n" +
+ " }\n" +
+ " catch (MultipleRowDbRecException e) {\n" +
+ " throw new InternalApplicationException(\"amending time sheet for \" + singleTimeSheetId, e);\n" +
+ " } catch (Exception e) {\n" +
+ " throw new InternalApplicationException(\"amending time sheet for \" + singleTimeSheetId, e);\n" +
+ " }\n" +
+ " return loadImpl();\n" +
+ " }\n" +
+ "\n" +
+ " TimeSheetTransactionApplier applyTransaction(TimeSheetIdentifier id, TimeEntryTransaction trans) {\n" +
+ " AllCalcDataManager updatedAcdm = getUpdatedAllCalcDataManager(id.getAsgnmt());\n" +
+ " AllCalculationData acd = getAllCalcData(updatedAcdm, id);\n" +
+ " return new TimeSheetTransactionApplier(trans, updatedAcdm, acd, parms, id);\n" +
+ " }\n" +
+ "\n" +
+ " private void recalc(TimeSheetIdentifier timeSheetId, Approval_event_type approvalEventType) {\n" +
+ " AllCalcDataManager updatedAcdm = getUpdatedAllCalcDataManager(timeSheetId.getAsgnmt());\n" +
+ " AllCalculationData acd = getAllCalcData(updatedAcdm, timeSheetId);\n" +
+ " try {\n" +
+ " if (approvalEventType == Approval_event_type.SAVE_SCHEDULE) {\n" +
+ " // if we're saving a change to the schedule, the timesheet might need to be re-initialized.\n" +
+ " acd.reinitTimeSheet(updatedAcdm, true);\n" +
+ " }\n" +
+ " acd.recalc(updatedAcdm);\n" +
+ " }\n" +
+ " catch (Exception e) {\n" +
+ " throw new InternalApplicationException(\"calculate for \" + timeSheetId, e);\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Save one timesheet to a ListWriter using AllCalculationData.\n" +
+ " * @param timeSheetId\n" +
+ " * @param saveEvent\n" +
+ " * @throws Exception\n" +
+ " */\n" +
+ " void save(TimeSheetIdentifier timeSheetId, Approval_event_type saveEvent) throws Exception {\n" +
+ " GeneratedId asgnmtId = timeSheetId.getAsgnmt();\n" +
+ " AllCalcDataManager acdMgr = getUpdatedAllCalcDataManager(asgnmtId);\n" +
+ " AllCalculationData acd = getAllCalcData(acdMgr, timeSheetId);\n" +
+ "\n" +
+ " // TODO: it'd be nice if we were able to retry a save if it failed because of unrelated changes (to accomodate for\n" +
+ " // concurrent save operations on other component timesheets besides the one that the user is trying to save)\n" +
+ " final ListWriter lw = new ListWriter();\n" +
+ " acd.saveAfterApplyingApprovalEvent(acdMgr, saveEvent, lw);\n" +
+ "\n" +
+ " //The exceptions must be generated after the ACD has performed approval related operations.\n" +
+ " // Loading the original ACD to get the timesheet object before the approval. This will be used to determine\n" +
+ " // timesheet's approval level before this save event.\n" +
+ " AllCalculationData originalAcd = getAllCalcData(getOriginalAllCalcDataManager(asgnmtId), timeSheetId);\n" +
+ " acdMgr.generateExceptionNotifications(acd, originalAcd.getTime_sheet(), acd.getTime_sheet(), lw);\n" +
+ " lw.writeLists();\n" +
+ "\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * If time sheets were saved and written to the database successfully, update internal data\n" +
+ " * to reflect what's in the database as the new \"original\" data.\n" +
+ " */\n" +
+ " void postSave() {\n" +
+ " originalAllCalcDataManager = updatedAllCalcDataManager;\n" +
+ " updatedAllCalcDataManager = null;\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Returns true if the given timesheet contains exceptions that should prevent save.\n" +
+ " * @param timeSheetId time sheet ID\n" +
+ " * @return true if exceptions exist that should prevent save, false otherwise.\n" +
+ " */\n" +
+ " boolean hasExceptionsPreventingSave(TimeSheetIdentifier timeSheetId) {\n" +
+ " AllCalculationData acd = getUpdatedAllCalcData(timeSheetId);\n" +
+ " try {\n" +
+ " return acd.getTime_sheet().getTime_sheet_exceptionList().getDisallow_timesheet_save(acd.getAllPolicies());\n" +
+ " }\n" +
+ " catch (PolicyLookupRequiredException e) {\n" +
+ " throw new InternalApplicationException(\"Policy error on timesheet \" + timeSheetId);\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Returns true if the given timesheet contains exceptions that should prevent submit.\n" +
+ " * @param timeSheetId time sheet ID\n" +
+ " * @return true if exceptions exist that should prevent submit, false otherwise.\n" +
+ " */\n" +
+ " boolean hasExceptionsPreventingSubmit(TimeSheetIdentifier timeSheetId) {\n" +
+ " AllCalculationData acd = getUpdatedAllCalcData(timeSheetId);\n" +
+ " try {\n" +
+ " return acd.getTime_sheet().getTime_sheet_exceptionList().getDisallow_timesheet_submit(acd.getAllPolicies());\n" +
+ " }\n" +
+ " catch (PolicyLookupRequiredException e) {\n" +
+ " throw new InternalApplicationException(\"Policy error on timesheet \" + timeSheetId);\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Compute {@link TimeEntryTransactionResults} changes to be returned in client.\n" +
+ " * @param timeSheetId\n" +
+ " * @param trans transaction which client just sent\n" +
+ " * @param applyResults results (errors) of applying the transaction\n" +
+ " * @param timeSheetSavedStatus a status to be added representing the save results - SAVED or ERROR, or null if none.\n" +
+ " * @param transactionSuccessful value for {@link TimeEntryTransactionResults#getTransactionWasSuccessful}.\n" +
+ " */\n" +
+ " TimeSheetDiff getDiff(TimeSheetIdentifier timeSheetId, TimeEntryTransaction trans,\n" +
+ " TimeSheetTransactionApplier applyResults, TransactionStatus timeSheetSavedStatus,\n" +
+ " boolean transactionSuccessful)\n" +
+ " {\n" +
+ " AllCalcDataManager acdm = getLatestAllCalcDataManager(timeSheetId.getAsgnmt());\n" +
+ " AllCalculationData acd = getAllCalcData(acdm, timeSheetId);\n" +
+ " NewToOldIdMap newToOldIdMap = applyResults.getNewToOldIdMap();\n" +
+ " StatusMapsForTimesheetAndSchedule timeSheetRowStatusMap = applyResults.getTimeEntryRowErrorMap();\n" +
+ "\n" +
+ " if (cat.isDebugEnabled()) {\n" +
+ " ObjectDumper.debug(cat, \"TimeSheetDiff getDiff before\", timeSheetRowStatusMap, null, true);\n" +
+ " }\n" +
+ "\n" +
+ " List<TransactionStatus> timeSheetStatuses = new ArrayList<TransactionStatus>(applyResults.getTimeSheetErrors());\n" +
+ " TimeSheetCounters counters = new TimeSheetCounters(trans, timeSheetId, newToOldIdMap);\n" +
+ " if (timeSheetSavedStatus != null) {\n" +
+ " timeSheetStatuses.add(timeSheetSavedStatus);\n" +
+ " if (timeSheetSavedStatus.getTransaction_status() == Transaction_status.SAVED ||\n" +
+ " timeSheetSavedStatus.getTransaction_status() == Transaction_status.ERROR) {\n" +
+ " // if we saved or there is an error mark every TimeEntryRow in the transaction as such.\n" +
+ " // get all row id's from the transaction (new id's - not temp id's)\n" +
+ " Collection transTimeSheetRowIds = applyResults.getTransactionTimeSheetRowIds();\n" +
+ " Collection transScheduleRowIds = applyResults.getTransactionScheduleRowIds();\n" +
+ " timeSheetRowStatusMap = new StatusMapsForTimesheetAndSchedule(transTimeSheetRowIds, transScheduleRowIds, timeSheetSavedStatus);\n" +
+ " timeSheetRowStatusMap.addAll(applyResults.getTimeEntryRowErrorMap());\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " if (cat.isDebugEnabled()) {\n" +
+ " ObjectDumper.debug(cat, \"TimeSheetDiff getDiff after\", timeSheetRowStatusMap, null, true);\n" +
+ " }\n" +
+ "\n" +
+ " CalcInfo calcInfo = new CalcInfo(acdm, acd, timeSheetId, parms);\n" +
+ " return new TimeSheetDiff(timeSheetId, acd, calcInfo, counters, newToOldIdMap, timeSheetStatuses,\n" +
+ " timeSheetRowStatusMap, transactionSuccessful, parms, trans);\n" +
+ " }\n" +
+ "\n" +
+ " TimeSheetCalculationInfo getCalculationInfo(TimeSheetIdentifier timeSheetIdentifier) {\n" +
+ " validate(timeSheetIdentifier);\n" +
+ " final AllCalcDataManager acdm = getLatestAllCalcDataManager(timeSheetIdentifier.getAsgnmt());\n" +
+ " return new CalcInfo(acdm, getAllCalcData(acdm, timeSheetIdentifier), timeSheetIdentifier, parms);\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Return the calculation info without auto-amending\n" +
+ " * @param acdm\n" +
+ " * @param timeSheetIdentifier\n" +
+ " * @return\n" +
+ " */\n" +
+ " private TimeSheetCalculationInfo getCalculationInfo(AllCalcDataManager acdm, TimeSheetIdentifier timeSheetIdentifier) {\n" +
+ " validate(timeSheetIdentifier);\n" +
+ " try {\n" +
+ " return new CalcInfo(acdm, acdm.getAllCalcData(timeSheetIdentifier.getPpEnd(), timeSheetIdentifier.getVersion()), timeSheetIdentifier, parms);\n" +
+ " } catch (Exception e) {\n" +
+ " throw new InternalApplicationException(\"Error creating CalcInfo \", e); \n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " private void invalidateAllCalcDataManagers() {\n" +
+ " originalAllCalcDataManager = null;\n" +
+ " updatedAllCalcDataManager = null;\n" +
+ " }\n" +
+ "\n" +
+ " private void createUpdatedAllCalcDataManager(Set<TimeSheetIdentifier> timeSheetIds) {\n" +
+ " AllCalcDataManager origAcdMgr = getOriginalAllCalcDataManager(asgnmtMaster.getAsgnmt());\n" +
+ " try {\n" +
+ " WDateList dateList = new WDateList();\n" +
+ " for(TimeSheetIdentifier id : timeSheetIds) {\n" +
+ " dateList.add(id.getPpEnd());\n" +
+ " }\n" +
+ " updatedAllCalcDataManager = origAcdMgr.copyForUpdate(dateList);\n" +
+ " } catch (Exception e) {\n" +
+ " throw new InternalApplicationException(\"Cloning for \" + timeSheetIds, e);\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " private void validate(TimeSheetIdentifier timeSheetId) throws IllegalArgumentException {\n" +
+ " if (!timeSheetIdentifiers.contains(timeSheetId)) {\n" +
+ " throw new IllegalArgumentException(\"Invalid time sheet specified: \" + timeSheetId\n" +
+ " + \". not in \" + timeSheetIdentifiers);\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Obtains the original AllCalcDataManager for the given assignment Id. The assignment id must be given because in a\n" +
+ " * multiple assignment environment, a specific component needs to be requested, as originalAllCalcDataManager refers\n" +
+ " * to the aggregate assignment.\n" +
+ " *\n" +
+ " * @param asgnmtId The id of the assignment to load.\n" +
+ " * @return the original AllCalcDataManager for the given assignment Id\n" +
+ " */\n" +
+ " private AllCalcDataManager getOriginalAllCalcDataManager(GeneratedId asgnmtId) {\n" +
+ " if(originalAllCalcDataManager == null) {\n" +
+ " originalAllCalcDataManager = createOriginalAllCalcDataManager();\n" +
+ " updatedAllCalcDataManager = null;\n" +
+ " }\n" +
+ "\n" +
+ " if(asgnmtId.equals(originalAllCalcDataManager.getAsgnmtId())) {\n" +
+ " return originalAllCalcDataManager;\n" +
+ " }\n" +
+ "\n" +
+ " return originalAllCalcDataManager.getAllCalcDataManager(asgnmtId);\n" +
+ " }\n" +
+ "\n" +
+ " private AllCalcDataManager createOriginalAllCalcDataManager() {\n" +
+ " AllPolicies allPolicies = PolicyManager.getInstance().getAllPolicies();\n" +
+ " try {\n" +
+ " return AllCalcDataManager.createForAsgnmt(asgnmtMaster, allPolicies);\n" +
+ " }\n" +
+ " catch (Exception e) {\n" +
+ " throw new InternalApplicationException(\"Failed to load ACDM for assignment with id:\"+asgnmtMaster.getAsgnmt(), e);\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Obtains the updated AllCalcDataManager for the given assignment Id. The assignment id must be given because in a\n" +
+ " * multiple assignment environment, a specific component needs to be requested, as originalAllCalcDataManager refers\n" +
+ " * to the aggregate assignment.\n" +
+ " *\n" +
+ " * @param asgnmtId The id of the assignment to load.\n" +
+ " * @return the updated AllCalcDataManager for the given assignment Id\n" +
+ " */\n" +
+ " private AllCalcDataManager getUpdatedAllCalcDataManager(GeneratedId asgnmtId) {\n" +
+ " if(updatedAllCalcDataManager == null) {\n" +
+ " throw new InternalApplicationException(\"Attempted to use the updated all calc data manager before it was created.\");\n" +
+ " }\n" +
+ "\n" +
+ " if(asgnmtId.equals(updatedAllCalcDataManager.getAsgnmtId())) {\n" +
+ " return updatedAllCalcDataManager;\n" +
+ " }\n" +
+ "\n" +
+ " return updatedAllCalcDataManager.getAllCalcDataManager(asgnmtId);\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Obtains the updated AllCalcDataManager for the given assignment Id, if present. If not present, returns the\n" +
+ " * original ACDM instead. The assignment id must be given because in a\n" +
+ " * multiple assignment environment, a specific component needs to be requested, as originalAllCalcDataManager refers\n" +
+ " * to the aggregate assignment.\n" +
+ " *\n" +
+ " * @param asgnmtId The id of the assignment to load.\n" +
+ " * @return he updated AllCalcDataManager for the given assignment Id, if present. If not present, returns the\n" +
+ " * original ACDM instead.\n" +
+ " */\n" +
+ " AllCalcDataManager getLatestAllCalcDataManager(GeneratedId asgnmtId) {\n" +
+ " if (updatedAllCalcDataManager != null) {\n" +
+ " return getUpdatedAllCalcDataManager(asgnmtId);\n" +
+ " }\n" +
+ "\n" +
+ " return getOriginalAllCalcDataManager(asgnmtId);\n" +
+ " }\n" +
+ "\n" +
+ " //todo-ute: the method name is misleading as it may also create a new amended ACD if period is amendable by system on user's behalf\n" +
+ " private AllCalculationData getAllCalcData(AllCalcDataManager mgr, TimeSheetIdentifier id) {\n" +
+ " try {\n" +
+ " EmployeePeriodInfo epInfo = mgr.getEmployeePeriodInfo(id.getPpEnd());\n" +
+ " if (epInfo == null) {\n" +
+ " final PolicyID asgnmtPolicyProfile = mgr.getAsgnmtMaster().getPolicy_profile(id.getPpEnd());\n" +
+ " final PolicyID policyProfileId = (asgnmtPolicyProfile == null) ? PolicyID.EMPTY_POLICYID : asgnmtPolicyProfile;\n" +
+ " throw new InvalidPayPeriodException(\"EmployeePeriodInfo could not be obtained for employee \" +\n" +
+ " id.getEmployee() + \" and assignment \" + id.getAsgnmt() + \" and period end - \" + id.getPpEnd() + \". \" +\n" +
+ " \"Possibly because the employee is not active on that date or there are not enough initialized policy profile \" +\n" +
+ " \"periods for policy profile \" + policyProfileId );\n" +
+ " }\n" +
+ "\n" +
+ " TimeSheetCalculationInfo calcInfo = this.getCalculationInfo(mgr, id);\n" +
+ " AssignmentPeriodState asgnmtPeriodState = calcInfo.getAssignmentPeriodState();\n" +
+ " TimeSheetState timesheetState = calcInfo.getTimeSheetState();\n" +
+ " //If requesting EDIT_VERSION, check to see if one exists or that period is amendable by the logged in user\n" +
+ " if (id.getVersion() == EmployeePeriodVersionInfo.EDIT_VERSION && !epInfo.hasEditVersion()\n" +
+ " && !isPeriodAmendable(epInfo, mgr, asgnmtPeriodState, timesheetState) ) {\n" +
+ " throw new InternalApplicationException(\"An editable timesheet could not be obtained for employee \" +\n" +
+ " id.getEmployee() + \" and period end - \" + id.getPpEnd());\n" +
+ " }\n" +
+ "\n" +
+ " //Check to see if an editable ACD is in ACD manager's cache - if one exists, use it\n" +
+ " //An empty unmodifiable ACD for a prior period might be in cache if an ACD for prior timesheet is requested and\n" +
+ " //if that's the case, we want to still be able to create an amended ACD\n" +
+ " final AllCalculationData acd = mgr.getAllCalcData(id.getPpEnd(),id.getVersion(),AllCalculationData.FETCH_CACHED_ONLY);\n" +
+ " if (acd != null && !acd.isUnmodifiable()) {\n" +
+ " return acd;\n" +
+ " }\n" +
+ "\n" +
+ " //Create an amended ACD only if the period is amendable and the logged in user can amend it\n" +
+ " if (isAmendableBySystemForUser(epInfo, mgr, asgnmtPeriodState)) {\n" +
+ " final AllCalculationData amendedAllCalcData = mgr.createAmendedAllCalcData(epInfo, parms.getApp_user(), WDateTime.now());\n" +
+ " // No need to hook this up to approval change logic, since it is an in-memory change so far.\n" +
+ " //Recalculate the amended ACD so that timesheet exceptions (if any) get created on the amended timesheet\n" +
+ " amendedAllCalcData.recalc(mgr);\n" +
+ " }\n" +
+ "\n" +
+ " //By this time, the ACD mgr's ACD cache will have the amended ACD if one's created in this method\n" +
+ " //and we can retrieve the cached amended ACD or the ACD from the database\n" +
+ " return mgr.getAllCalcData(id.getPpEnd(), id.getVersion());\n" +
+ " } catch(InvalidPayPeriodException e) {\n" +
+ " //Rethrow InvalidPeriodExceptions--don't wrap them. We want them to be typed as InvalidPeriodExceptions.\n" +
+ " throw e;\n" +
+ " } catch (Exception e) {\n" +
+ " throw new InternalApplicationException(\"Timesheet could not be obtained for employee \" +\n" +
+ " id.getEmployee() + \", assignment \" + id.getAsgnmt()+ \", period end \" + id.getPpEnd() + \" and version \" + id.getVersion() + \".\", e);\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * A period is amendable if one of the following is true:\n" +
+ " * <pre>\n" +
+ " * - {@link #isAmendableBySystemForUser(EmployeePeriodInfo, AllCalcDataManager, AssignmentPeriodState)\n" +
+ " * amendable by system on users's behalf}\n" +
+ " * - {@link TimeSheetState#isAmendable() amendable directly by user} generally by clicking \"Amend\" button on\n" +
+ " * prior active period with one or more closed timesheets\n" +
+ " * </pre>\n" +
+ " */\n" +
+ " private static boolean isPeriodAmendable(EmployeePeriodInfo epInfo, AllCalcDataManager mgr,\n" +
+ " AssignmentPeriodState asgnmtPeriodState, TimeSheetState timesheetState)\n" +
+ " throws SQLException, MultipleRowDbRecException {\n" +
+ " return timesheetState.isAmendable() || isAmendableBySystemForUser(epInfo, mgr, asgnmtPeriodState);\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * A period is amendable by system on user's behalf (not the same as AUTO_AMEND or SYS_AMEND which are also created by\n" +
+ " * system) if user has amend rights for the specified period as of today and if specified period is a priod period\n" +
+ " * with no timesheet or it's a prior period timesheet with just system amended but not user amended\n" +
+ " * @param epInfo\n" +
+ " * @param mgr\n" +
+ " * @param asgnmtPeriodState\n" +
+ " * @return\n" +
+ " * @throws PolicyLookupException\n" +
+ " * @throws MultipleRowDbRecException\n" +
+ " * @throws SQLException\n" +
+ " * @see AssignmentPeriodState#isPeriodAmendable() \n" +
+ " * @see Approval_event_type#SYS_AMEND\n" +
+ " * @see Approval_event_type#AMEND\n" +
+ " */\n" +
+ " private static boolean isAmendableBySystemForUser(EmployeePeriodInfo epInfo, AllCalcDataManager mgr,\n" +
+ " AssignmentPeriodState asgnmtPeriodState)\n" +
+ " throws MultipleRowDbRecException, SQLException {\n" +
+ " return asgnmtPeriodState.isPeriodAmendable() && // TODO: this doesn't match the javadoc?\n" +
+ " ( mgr.isPriorModifiablePeriodWithNoTimesheet(epInfo) || epInfo.isPriorPeriodWithSysAmendVersionOnly() );\n" +
+ " }\n" +
+ "\n" +
+ " private AllCalculationData getOriginalAllCalcData(TimeSheetIdentifier timeSheetIdentifier) {\n" +
+ " return getAllCalcData(getOriginalAllCalcDataManager(timeSheetIdentifier.getAsgnmt()), timeSheetIdentifier);\n" +
+ " }\n" +
+ "\n" +
+ " private AllCalculationData getUpdatedAllCalcData(TimeSheetIdentifier timeSheetIdentifier) {\n" +
+ " return getAllCalcData(getUpdatedAllCalcDataManager(timeSheetIdentifier.getAsgnmt()), timeSheetIdentifier);\n" +
+ " }\n" +
+ "\n" +
+ "\n" +
+ " private Set<TimeSheetIdentifier> getTimeSheetIdentifiers() {\n" +
+ " return timeSheetIdentifiers;\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Returns the pay period end for the period containing date provided, relative\n" +
+ " * to the defined periods for this assignment.\n" +
+ " *\n" +
+ " * @param aDateInUnknownPeriod any date we want to know the period for\n" +
+ " * @return never null\n" +
+ " */\n" +
+ " WDate getPpEndForDate(GeneratedId asgnmtId, WDate aDateInUnknownPeriod) {\n" +
+ " return TimeSchedUtils.getPpEndForDate(getOriginalAllCalcDataManager(asgnmtId), aDateInUnknownPeriod);\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Assign system_record_id's to any DbRec objecs in the collection which lack them.\n" +
+ " * @param dbRecList List of DbRec objects on which to check the system_record_id. Records in list will be modified.\n" +
+ " */\n" +
+ " static private void assignSystemRecordIds(ListWrapBase dbRecList) {\n" +
+ " for (Iterator iterator = dbRecList.getCollection().iterator(); iterator.hasNext();) {\n" +
+ " DbRec dbRec = (DbRec) iterator.next();\n" +
+ " assignSystemRecordId(dbRec);\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Assign system_record_id to a DbRec object, if it is not set or contains a temporary id.\n" +
+ " * @param dbRec DbRec objects on which to check/change the system_record_id.\n" +
+ " */\n" +
+ " static private void assignSystemRecordId(DbRec dbRec) {\n" +
+ " if (dbRec.getSystem_record_id() == null || dbRec.getSystem_record_id().requiresPermanentId()) {\n" +
+ " dbRec.setSystem_record_id(SystemId.getNewID());\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Removes the last approval event (employee approval) from approval event list from the AllCalculationData object of\n" +
+ " * {@link #updatedAllCalcDataManager}\n" +
+ " * @param timeSheetId - Used to get the {@link AllCalculationData} object from {@link #updatedAllCalcDataManager}\n" +
+ " */\n" +
+ " void undoEmployeeApproval(TimeSheetIdentifier timeSheetId) {\n" +
+ " final AllCalculationData updatedAllCalcData = getUpdatedAllCalcData(timeSheetId);\n" +
+ " updatedAllCalcData.getApproval_eventList().removeLastApprovalEvent();\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Update the current object to be able to be used for other timesheets for this assignment\n" +
+ " * @param parms\n" +
+ " * @param timeSheetIdentifiers\n" +
+ " */\n" +
+ " public void update(TimeEntryParmsPerAssignment parms, Set<TimeSheetIdentifier> timeSheetIdentifiers) {\n" +
+ " setClassFields(parms, timeSheetIdentifiers);\n" +
+ " }\n" +
+ "\n" +
+ " private void setClassFields(TimeEntryParmsPerAssignment parms, Set<TimeSheetIdentifier> timeSheetIdentifiers) {\n" +
+ " this.parms = parms;\n" +
+ " this.timeSheetIdentifiers = TimeEntryParmsPerAssignment.TIMESHEET_IDENTIFIER_TREESET_FACTORY.newInstance();\n" +
+ " this.timeSheetIdentifiers.addAll(timeSheetIdentifiers);\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Recalculates and Saves timesheets (if saveData == true) for timesheet ids in {@link #parms} that belong to this\n" +
+ " * assignment\n" +
+ " *\n" +
+ " * @param trans\n" +
+ " * @return AggregateTimeEntryTransactionResults for all saved timesheets\n" +
+ " * @throws Exception in case of fatal error during timesheet recalc & save e.g. errors while store data in DB etc.\n" +
+ " * This precludes ConcurrentUserModification exception. Any exception thrown from this method, eventually gets\n" +
+ " * escalated as transaction exception\n" +
+ " */\n" +
+ " public TimeEntryTransactionResults recalcAndSaveTimesheets(TimeEntryTransaction trans, boolean saveData) throws Exception {\n" +
+ " // TODO-13285: Remove this code and implement merging concurrently modified time sheets\n" +
+ " AllCalcDataManager tempAcdMgr = null;\n" +
+ " AggregateTimeEntryTransactionResults results = (AggregateTimeEntryTransactionResults) parms.getTimeEntryResultsFactory().newInstance();\n" +
+ " Set<TimeSheetIdentifier> timeSheetIds = getAffectedTimeSheetIdentifiers(trans, parms);\n" +
+ " int retryCount = 0;\n" +
+ " boolean canRetryConcurrentModification = true;\n" +
+ " if (timeSheetIds.isEmpty()) {\n" +
+ " return results;\n" +
+ " }\n" +
+ "\n" +
+ " assert timeSheetIdentifiers.containsAll(timeSheetIds) : \"Attempted to recalculate a timesheet identifier not managed by this AssignmentManager.\";\n" +
+ " createUpdatedAllCalcDataManager(timeSheetIds);\n" +
+ "\n" +
+ " TransactionStatus timeSheetSaveStatus = null;\n" +
+ " Map<TimeSheetIdentifier, TimeSheetTransactionApplier> applyResultsMap = new HashMap<TimeSheetIdentifier, TimeSheetTransactionApplier>();\n" +
+ " for (TimeSheetIdentifier timeSheetId : timeSheetIds) {\n" +
+ " TimeSheetTransactionApplier applyResults = applyTransaction(timeSheetId, trans);\n" +
+ " if(applyResults.getApprovalEventType() != Approval_event_type.SAVE_SCHEDULE) {\n" +
+ " applyResultsMap.put(timeSheetId, applyResults);\n" +
+ " }\n" +
+ "\n" +
+ " recalc(timeSheetId, applyResults.getApprovalEventType());\n" +
+ "\n" +
+ " boolean isWithdrawal =\n" +
+ " (trans.findTransactionApprovalEvent(timeSheetId, Approval_event_type.WITHDRAWAL) != null);\n" +
+ " if (!isWithdrawal) {\n" +
+ " // There are 3 conditions identified in the following if statement that can prevent an \"action\" on the\n" +
+ " // current timesheet. The first is an exception that prevents save. In this case, we should never allow a\n" +
+ " // save of the timesheet to occur. The second condition is an exception that prevents submit. In this\n" +
+ " // condition, we should only allow a save if the user is not attempting to submit (apply an APPROVAL event).\n" +
+ " // The third case is errors that occur while applying transactions to the timesheet. An example of when this\n" +
+ " // may occur is if the same time sheet detail row is modified by 2 users. In all of these cases we prevent\n" +
+ " // the save operation from executing.\n" +
+ " // In the next condition where we check if an error has occurred, we remove the last approval event from the\n" +
+ " // timesheet if we did not save AND it was a submit (APPROVAL) event. Transactions only allow 1 event to be applied\n" +
+ " // to the timesheet. The transaction explicitly excludes SAVE_TIME_SHEET and SAVE_SCHEDULE events from being applied.\n" +
+ " // It relies on these events being applied only by the save operation itself. As a result, a maximum of 2 events may\n" +
+ " // be added to the timesheet as a result of the transaction (the event on the transaction if it was not a save event)\n" +
+ " // and the SAVE_TIME_SHEET or SAVE_SCHEDULE event added during the save operation.\n" +
+ "\n" +
+ " if (hasSubmitEvent(trans, timeSheetId) &&\n" +
+ " hasExceptionsPreventingSubmit(timeSheetId)) {\n" +
+ " timeSheetSaveStatus = getHighestPriorityError(timeSheetSaveStatus, Messages.EXCEPTIONS_PREVENT_SUBMIT);\n" +
+ " }\n" +
+ "\n" +
+ " if (hasExceptionsPreventingSave(timeSheetId)) {\n" +
+ " timeSheetSaveStatus = new TransactionStatusImpl(Transaction_status.ERROR,\n" +
+ " Messages.EXCEPTIONS_PREVENT_SAVE.getLabel());\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " if (applyResults.hasErrors()) {\n" +
+ " timeSheetSaveStatus = new TransactionStatusImpl(Transaction_status.ERROR,\n" +
+ " Messages.TIME_SHEET_EXCEPTION_JAVA_EXCEPTION .getLabel());\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ "\n" +
+ " boolean errorPreventsAction = (timeSheetSaveStatus != null);\n" +
+ "\n" +
+ "\n" +
+ " Approval_event lastOriginalApprovalEvent = null;\n" +
+ " for (TimeSheetIdentifier timeSheetId : timeSheetIds) {\n" +
+ " TimeSheetTransactionApplier applyResults = applyResultsMap.get(timeSheetId);\n" +
+ " try {\n" +
+ " while (saveData && canRetryConcurrentModification) {\n" +
+ " if (errorPreventsAction) {\n" +
+ " // If the changes were not saved due to errors, and this operation (transaction) was an employee timesheet submission,\n" +
+ " // remove the approval event from the unsaved ACD.\n" +
+ " // NOTE: We do not have to concern ourselves with removing SAVE_TIME_SHEET or SAVE_SCHEDULE events here as these events\n" +
+ " // are explicitly EXCLUDED in the TimeSheetTransactionApplier (not applied) and are applied by the save operation (which\n" +
+ " // has not executed if we made it here.\n" +
+ " if (hasSubmitEvent(trans, timeSheetId)) {\n" +
+ " undoEmployeeApproval(timeSheetId);\n" +
+ " }\n" +
+ " } else {\n" +
+ " save(timeSheetId, applyResults.getApprovalEventType());\n" +
+ " timeSheetSaveStatus = new TransactionStatusImpl(Transaction_status.SAVED,\n" +
+ " Messages.TIME_SHEET_SAVED.getLabel());\n" +
+ " postSave();\n" +
+ " }\n" +
+ " // All operations completed, so retries are no longer necessary\n" +
+ " canRetryConcurrentModification = false;\n" +
+ " }\n" +
+ " } catch (ConcurrentUserModificationException ex) {\n" +
+ " // Store the old AcdMgr, when a concurrent mod error due to another user modifying a time sheet occurs we want\n" +
+ " // to receive the same new approval events to ensure that the user is forced to reload the time sheet to continue.\n" +
+ " // TODO-13285: Remove the tempAcdMgr and make merging concurrently modified time sheets possible,\n" +
+ " // TODO-13285: requires considering multiple edge cases for the user interface\n" +
+ " if (tempAcdMgr == null) {\n" +
+ " tempAcdMgr = getOriginalAllCalcDataManager(asgnmtMaster.getAsgnmt());\n" +
+ " }\n" +
+ "\n" +
+ " if (retryCount == MAX_RETRIES) {\n" +
+ " // return the acdMgr to its previous state, this ensures the user must reload the time sheet\n" +
+ " // TODO-13285: Remove this code and implement merging concurrently modified time sheets\n" +
+ " originalAllCalcDataManager = tempAcdMgr;\n" +
+ " GeneratedId errorId = ServerErrorLogger.singleton.log(new ServerError(\"Exception saving time sheet\", ex,\n" +
+ " Program_source.SERVER_REQUEST, parms.getApp_user().getLogin_id()));\n" +
+ " cat.error(\"Unable to save time sheet. debug_error_log id:\" + errorId, ex);\n" +
+ " //Use timeSheetSaveStatus to send concurrent error message to user.\n" +
+ " errorPreventsAction = true;\n" +
+ " timeSheetSaveStatus = new TransactionStatusImpl(Transaction_status.ERROR,\n" +
+ " Messages.TIME_SHEET_EXCEPTION_CONCURRENT_USER.getLabel());\n" +
+ " // We have retried saving and have hit the MAX_RETRIES threshold, so stop retrying.\n" +
+ " canRetryConcurrentModification = false;\n" +
+ " } else {\n" +
+ " // On the first retry, we need to capture the last (most recent) approval event that existed on this timesheet prior to applying\n" +
+ " // any transactions because when we reload the \"original\" ACD to attempt to reapply the transactions we will lose track\n" +
+ " // of this (we'll pull in approval events for transactions that were saved in other sessions/processes). This is necessary to\n" +
+ " // allow more than 1 retry\n" +
+ " if (lastOriginalApprovalEvent == null) {\n" +
+ " lastOriginalApprovalEvent = getAllCalcData(getOriginalAllCalcDataManager(timeSheetId.getAsgnmt()), timeSheetId).getApproval_eventList().getLastApprovalEvent();\n" +
+ " }\n" +
+ " retryCount++;\n" +
+ " // attempt to reapply the transaction\n" +
+ " try {\n" +
+ " applyResults = attemptTimeSheetTransactionReapply(trans, timeSheetId, lastOriginalApprovalEvent);\n" +
+ " } catch (ConcurrentUserModificationException cume) {\n" +
+ " // return the acdMgr to its previous state, this ensures the user must reload the time sheet\n" +
+ " // TODO-13285: Remove this code and implement merging concurrently modified time sheets\n" +
+ " originalAllCalcDataManager = tempAcdMgr;\n" +
+ " // if we were unable to reapply transactions, no further retries are necessary (because it will just keep failing)\n" +
+ " // subsequent retries only succeed if we were able to reapply the new transactions successfully and still received\n" +
+ " // another ConcurrentUserModificationException (a second change occurred while applying transactions)\n" +
+ " canRetryConcurrentModification = false;\n" +
+ " errorPreventsAction = true;\n" +
+ " timeSheetSaveStatus = new TransactionStatusImpl(Transaction_status.ERROR,\n" +
+ " Messages.TIME_SHEET_EXCEPTION_CONCURRENT_USER.getLabel());\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ " results.add(getDiff(timeSheetId, trans, applyResults, timeSheetSaveStatus, !errorPreventsAction));\n" +
+ " }\n" +
+ " return results;\n" +
+ " }\n" +
+ "\n" +
+ " ";
+
+ String part2 = "\n" +
+ " private TransactionStatus getHighestPriorityError(TransactionStatus existingStatus, Message newError) {\n" +
+ " if(existingStatus == null) {\n" +
+ " return newError;\n" +
+ " }\n" +
+ " TransactionStatus timeSheetSaveStatus = new TransactionStatusImpl(Transaction_status.ERROR,\n" +
+ " );\n" +
+ " return timeSheetSaveStatus;\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Returns true if the given TimeEntryTransaction has a submit event for the given time sheet.\n" +
+ " * @param trans TimeEntryTransaction to search\n" +
+ " * @param timeSheetId time sheet to search\n" +
+ " * @return true if a submit event exists\n" +
+ " */\n" +
+ " private static boolean hasSubmitEvent(TimeEntryTransaction trans, TimeSheetIdentifier timeSheetId) {\n" +
+ " return trans.findTransactionApprovalEvent(timeSheetId, Approval_event_type.APPROVAL) != null;\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Resolves modifications that impact only non-\"input\" values on the timesheet to prevent them\n" +
+ " * from causing ConcurrentUserModificationExceptions on subsequent attempts at saving the data\n" +
+ " * @param trans time entry transaction to resolve\n" +
+ " * @param id time sheet ID\n" +
+ " * @param lastApprovalEvent the most recent approval event on the timesheet prior to any transactions\n" +
+ " * @return TimeSheetTransactionApplier if transactions were reapplied\n" +
+ " * @throws Exception on error loading the acd\n" +
+ " */\n" +
+ " private TimeSheetTransactionApplier attemptTimeSheetTransactionReapply(final TimeEntryTransaction trans, final TimeSheetIdentifier id, Approval_event lastApprovalEvent) throws Exception {\n" +
+ " // Clean out the ACDM cache to force reloads of the data from the database\n" +
+ " invalidateAllCalcDataManagers();\n" +
+ " AllCalculationData originalAcd = getAllCalcData(getOriginalAllCalcDataManager(id.getAsgnmt()), id);\n" +
+ " // Get any new approval events that exist in the database\n" +
+ " Approval_eventList newApprovalEvents = originalAcd.getApproval_eventList().getApprovalsSince(lastApprovalEvent);\n" +
+ " // Check if a \"concurrent save\" is possible given the events that have occurred\n" +
+ " if (newApprovalEvents.canConcurrentSave()) {\n" +
+ " //TODO:FIX\n" +
+ " //createUpdatedAllCalcDataManager(listOfAllIdsHere);\n" +
+ " TimeSheetTransactionApplier applyResults = applyTransaction(id, trans); // reapply transactions\n" +
+ " recalc(id, applyResults.getApprovalEventType()); // recalculate\n" +
+ " DbRecTime_sheet originalTimeSheet = originalAcd.getTime_sheet();\n" +
+ " DbRecTime_sheet updatedTimeSheet = getAllCalcData(getUpdatedAllCalcDataManager(id.getAsgnmt()), id).getTime_sheet();\n" +
+ " // Copy the system fields from the original time sheet to the updated time sheet because\n" +
+ " // we have determined at this point that the concurrent save is okay based on the difference\n" +
+ " // between these 2 time sheets. Copying these fields over will allow the save to complete\n" +
+ " // without causing a ConcurrentUserModificationException by making the update counter match.\n" +
+ " DbRecFieldCopier copier = new DbRecFieldCopier(DataDictionary.getCltnOfSystemFieldNames());\n" +
+ " copier.copyFields(originalTimeSheet, updatedTimeSheet);\n" +
+ " return applyResults;\n" +
+ " } else {\n" +
+ " // Otherwise, throw the exception\n" +
+ " throw new ConcurrentUserModificationException(\"Unable to save time sheet for assignment \" + originalAcd.getAsgnmtId() + \"due to concurrent changes.\");\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Returns a set of AssignmentManagers that are affected by changes in the given transaction and managed by this\n" +
+ " * TimeEntryManager.\n" +
+ " *\n" +
+ " * @return a set of AssignmentManagers that are affected by changes in the given transaction and managed by this\n" +
+ " * TimeEntryManager.\n" +
+ " */\n" +
+ " public Set<TimeSheetIdentifier> getAffectedTimeSheetIdentifiers(TimeEntryTransaction transaction, TimeEntryParmsPerAssignment parms) {\n" +
+ " Set<TimeSheetIdentifier> affectedTimeSheetIds = new HashSet<TimeSheetIdentifier>();\n" +
+ " for(GeneratedId assignmentId : getAssignmentIds()) {\n" +
+ " for(TimeSheetIdentifier timeSheetId : parms.getTimeSheetIdentifiersForAssignment(assignmentId)) {\n" +
+ " if(!transaction.obtainAllRows(timeSheetId).isEmpty()) {\n" +
+ " affectedTimeSheetIds.add(timeSheetId);\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ " return affectedTimeSheetIds;\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Obtains all assignment id's that are managed by this AssignmentManager.\n" +
+ " *\n" +
+ " * @return all assignment id's that are managed by this AssignmentManager.\n" +
+ " */\n" +
+ " public Set<GeneratedId> getAssignmentIds() {\n" +
+ " Set<GeneratedId> assignmentIds = new HashSet<GeneratedId>();\n" +
+ " Asgnmt_masterList amList = asgnmtMaster.getCompAsgnmtMasters();\n" +
+ " for(Asgnmt_master am : amList) {\n" +
+ " assignmentIds.add(am.getAsgnmt());\n" +
+ " }\n" +
+ " return assignmentIds;\n" +
+ " }\n" +
+ "\n" +
+ " public GeneratedId getEmployee() {\n" +
+ " return asgnmtMaster.getEmployee();\n" +
+ " }\n" +
+ "\n" +
+ " /** Single or aggregate assignment master associated with this manager */\n" +
+ " private final Asgnmt_master asgnmtMaster;\n" +
+ "\n" +
+ " private TimeEntryParmsPerAssignment parms;\n" +
+ "\n" +
+ " /** Set of {@link TimeSheetIdentifier}'s which are managed by this object.\n" +
+ " * Composed of all the identifiers in the TimeEntryParms for this assignment and related components.\n" +
+ " */\n" +
+ " private Set<TimeSheetIdentifier> timeSheetIdentifiers;\n" +
+ "\n" +
+ " /**\n" +
+ " * Original Single or Aggregate ACDM, as loaded from the database. ACD's in here are not modified.\n" +
+ " * This ACDM is lazily loaded, and should always be obtained from {@link #getOriginalAllCalcDataManager(GeneratedId)}.\n" +
+ " *\n" +
+ " * Null means that the ACDM has not yet been loaded from the database, and any attempts to use it should first\n" +
+ " * initialize it. Note: The meaning of null is different than updatedAllCalcDataManager's null meaning.\n" +
+ " */\n" +
+ " private AllCalcDataManager originalAllCalcDataManager = null;\n" +
+ "\n" +
+ " /**\n" +
+ " * Updated Single or Aggregate ACDM--a shallow copy of originalAllCalcDataManager. ACD's in here are modified by\n" +
+ " * TimeEntryTransactions. This ACDM is NOT lazily loaded--null means no changes present, and non-null means the\n" +
+ " * updated ACDM has been explicitly created.\n" +
+ " *\n" +
+ " * Null means that no changes have been made to the ACDM or data, and any attempts to use it should either throw a\n" +
+ " * descriptive error, or explicitly create the updatedAllCalcDataManager.\n" +
+ " * Note: The meaning of null is different than originalAllCalcDataManager's null meaning.\n" +
+ " */\n" +
+ " private AllCalcDataManager updatedAllCalcDataManager = null;\n" +
+ "\n" +
+ " private static final int MAX_RETRIES = 2;\n" +
+ "\n" +
+ " private static final Category cat=Category.getInstance(AssignmentManager.class.getName());\n" +
+ "}";
+ configureFromFileText("Foo.java", part1 + part2);
+
+ final PsiDocumentManager docManager = PsiDocumentManager.getInstance(ourProject);
+ final Document doc = docManager.getDocument(myFile);
+ doc.insertString(part1.length(), "/**");
+
+ boolean old = DebugUtil.CHECK;
+ DebugUtil.CHECK = true;
+ try {
+ docManager.commitAllDocuments();
+ }
+ finally {
+ DebugUtil.CHECK = old;
+ }
+ }
+}