This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 209798
Collapse All | Expand All

(-)a/java.source/apichanges.xml (+14 lines)
Lines 108-113 Link Here
108
    <!-- ACTUAL CHANGES BEGIN HERE: -->
108
    <!-- ACTUAL CHANGES BEGIN HERE: -->
109
109
110
    <changes>
110
    <changes>
111
        <change id="GeneratorUtilities-createFromTemplate">
112
             <api name="general"/>
113
             <summary>Added <code>GeneratorUtilities.createFromTemplate</code>.</summary>
114
             <version major="0" minor="100"/>
115
             <date day="5" month="4" year="2012"/>
116
             <author login="ralphbenjamin"/>
117
             <compatibility addition="yes" binary="compatible" semantic="compatible" source="compatible" deletion="no" deprecation="no" modification="no"/>
118
             <description>
119
                 Added the method <code>createFromTemplate</code> to class <code>GeneratorUtilities</code>,
120
                 which will create a new CompilationUnitTree from a template.
121
             </description>
122
             <class package="org.netbeans.api.java.source" name="GeneratorUtilities"/>
123
             <issue number="209798"/>
124
        </change>
111
        <change id="GeneratorUtilities-appendToAnnotationValue">
125
        <change id="GeneratorUtilities-appendToAnnotationValue">
112
             <api name="general"/>
126
             <api name="general"/>
113
             <summary>Added <code>GeneratorUtilities.appendToAnnotationValue</code>.</summary>
127
             <summary>Added <code>GeneratorUtilities.appendToAnnotationValue</code>.</summary>
(-)a/java.source/src/org/netbeans/api/java/source/AssignComments.java (-1 / +1 lines)
Lines 106-112 Link Here
106
            boolean oldMapComments = mapComments;
106
            boolean oldMapComments = mapComments;
107
            try {
107
            try {
108
                mapComments |= tree == commentMapTarget;
108
                mapComments |= tree == commentMapTarget;
109
                if ((commentMapTarget != null) && info.getTreeUtilities().isSynthetic(new TreePath(new TreePath(info.getCompilationUnit()), tree)))
109
                if ((commentMapTarget != null) && info.getTreeUtilities().isSynthetic(new TreePath(new TreePath(unit), tree)))
110
                    return null;
110
                    return null;
111
                if (commentMapTarget != null) {
111
                if (commentMapTarget != null) {
112
                    mapComments2(tree, true);
112
                    mapComments2(tree, true);
(-)a/java.source/src/org/netbeans/api/java/source/GeneratorUtilities.java (+30 lines)
Lines 120-125 Link Here
120
import javax.lang.model.util.Elements;
120
import javax.lang.model.util.Elements;
121
import javax.swing.text.Document;
121
import javax.swing.text.Document;
122
import javax.swing.text.JTextComponent;
122
import javax.swing.text.JTextComponent;
123
import javax.tools.JavaFileObject;
123
124
124
import org.netbeans.api.editor.EditorRegistry;
125
import org.netbeans.api.editor.EditorRegistry;
125
import org.netbeans.api.java.lexer.JavaTokenId;
126
import org.netbeans.api.java.lexer.JavaTokenId;
Lines 127-136 Link Here
127
import org.netbeans.editor.GuardedDocument;
128
import org.netbeans.editor.GuardedDocument;
128
import org.netbeans.modules.java.source.builder.CommentHandlerService;
129
import org.netbeans.modules.java.source.builder.CommentHandlerService;
129
import org.netbeans.modules.java.source.builder.CommentSetImpl;
130
import org.netbeans.modules.java.source.builder.CommentSetImpl;
131
import org.netbeans.modules.java.source.parsing.FileObjects;
130
import org.netbeans.modules.java.source.parsing.SourceFileObject;
132
import org.netbeans.modules.java.source.parsing.SourceFileObject;
131
import org.netbeans.modules.java.source.query.CommentSet.RelativePosition;
133
import org.netbeans.modules.java.source.query.CommentSet.RelativePosition;
132
import org.netbeans.modules.java.source.save.DiffContext;
134
import org.netbeans.modules.java.source.save.DiffContext;
133
import org.openide.cookies.EditorCookie;
135
import org.openide.cookies.EditorCookie;
136
import org.openide.filesystems.FileObject;
137
import org.openide.filesystems.FileUtil;
134
import org.openide.loaders.DataObject;
138
import org.openide.loaders.DataObject;
135
import org.openide.util.Exceptions;
139
import org.openide.util.Exceptions;
136
140
Lines 159-164 Link Here
159
    }
163
    }
160
164
161
    /**
165
    /**
166
     * Create a new CompilationUnitTree from a template.
167
     *
168
     * @param sourceRoot a source root under which the new file is created
169
     * @param path a relative path to file separated by '/'
170
     * @param kind the kind of Element to use for the template, can be null or
171
     * CLASS, INTERFACE, ANNOTATION_TYPE, ENUM, PACKAGE
172
     * @return new CompilationUnitTree created from a template
173
     * @throws IOException when an exception occurs while creating the template
174
     * @since 0.100
175
     */
176
    public CompilationUnitTree createFromTemplate(FileObject sourceRoot, String path, ElementKind kind) throws IOException {
177
        String[] nameComponent = FileObjects.getFolderAndBaseName(path, '/');
178
        JavaFileObject sourceFile = FileObjects.templateFileObject(sourceRoot, nameComponent[0], nameComponent[1]);
179
        FileObject template = FileUtil.getConfigFile(copy.template(kind));
180
        FileObject targetFile = copy.doCreateFromTemplate(template, sourceFile);
181
        CompilationUnitTree templateCUT = copy.impl.getJavacTask().parse(FileObjects.nbFileObject(targetFile, targetFile.getParent())).iterator().next();
182
        CompilationUnitTree importComments = GeneratorUtilities.get(copy).importComments(templateCUT, templateCUT);
183
        CompilationUnitTree result = copy.getTreeMaker().CompilationUnit(importComments.getPackageAnnotations(),
184
                sourceRoot,
185
                path,
186
                importComments.getImports(),
187
                importComments.getTypeDecls());
188
        return result;
189
    }
190
191
    /**
162
     * Inserts a member to a class. Using the rules specified in the {@link CodeStyle}
192
     * Inserts a member to a class. Using the rules specified in the {@link CodeStyle}
163
     * it finds the proper place for the member and calls {@link TreeMaker.insertClassMember}
193
     * it finds the proper place for the member and calls {@link TreeMaker.insertClassMember}
164
     *
194
     *
(-)a/java.source/src/org/netbeans/api/java/source/WorkingCopy.java (-16 / +58 lines)
Lines 74-79 Link Here
74
import java.util.logging.Level;
74
import java.util.logging.Level;
75
import java.util.logging.Logger;
75
import java.util.logging.Logger;
76
import javax.lang.model.element.Element;
76
import javax.lang.model.element.Element;
77
import javax.lang.model.element.ElementKind;
77
import javax.swing.text.BadLocationException;
78
import javax.swing.text.BadLocationException;
78
import javax.tools.JavaFileObject;
79
import javax.tools.JavaFileObject;
79
80
Lines 197-213 Link Here
197
    
198
    
198
    /**
199
    /**
199
     * Replaces the original tree <code>oldTree</code> with the new one -
200
     * Replaces the original tree <code>oldTree</code> with the new one -
200
     * <code>newTree</code>. <code>null</code> values are not allowed.
201
     * <code>newTree</code>.
201
     * Use methods in {@link TreeMaker} for tree element removal.
202
     * <p>
203
     * To create a new file, use
204
     * <code>rewrite(null, compilationUnitTree)</code>. Use
205
     * {@link GeneratorUtilities#createFromTemplate GeneratorUtilities.createFromTemplate()}
206
     * to create a new compilation unit tree from a template.
207
     * <p>
208
     * <code>newTree</code> cannot be <code>null</code>, use methods in
209
     * {@link TreeMaker} for tree element removal. If <code>oldTree</code> is
210
     * null, <code>newTree</code> must be of kind
211
     * {@link Kind#COMPILATION_UNIT COMPILATION_UNIT}.
212
     * 
202
     * 
213
     * 
203
     * @param oldTree  tree to be replaced, use tree already represented in
214
     * @param oldTree  tree to be replaced, use tree already represented in
204
     *                 source code.
215
     *                 source code. <code>null</code> to create a new file.
205
     * @param newTree  new tree, either created by <code>TreeMaker</code>
216
     * @param newTree  new tree, either created by <code>TreeMaker</code>
206
     *                 or obtained from different place.
217
     *                 or obtained from different place. <code>null</code>
218
     *                 values are not allowed.
207
     * @throws IllegalStateException if <code>toPhase()</code> method was not
219
     * @throws IllegalStateException if <code>toPhase()</code> method was not
208
     *         called before.
220
     *         called before.
209
     * @throws IllegalArgumentException when <code>null</code> was passed to the 
221
     * @throws IllegalArgumentException when <code>null</code> was passed to the 
210
     *         method.
222
     *         method.
223
     * @see GeneratorUtilities#createFromTemplate
211
     * @see TreeMaker
224
     * @see TreeMaker
212
     */
225
     */
213
    public synchronized void rewrite(@NullAllowed Tree oldTree, @NonNull Tree newTree) {
226
    public synchronized void rewrite(@NullAllowed Tree oldTree, @NonNull Tree newTree) {
Lines 550-557 Link Here
550
            try {
563
            try {
551
                FileObject targetFile = doCreateFromTemplate(t);
564
                FileObject targetFile = doCreateFromTemplate(t);
552
                CompilationUnitTree templateCUT = impl.getJavacTask().parse(FileObjects.nbFileObject(targetFile, targetFile.getParent())).iterator().next();
565
                CompilationUnitTree templateCUT = impl.getJavacTask().parse(FileObjects.nbFileObject(targetFile, targetFile.getParent())).iterator().next();
566
                CompilationUnitTree importComments = GeneratorUtilities.get(this).importComments(templateCUT, templateCUT);
553
567
554
                changes.put(templateCUT, t);
568
                changes.put(importComments, t);
555
569
556
                StringWriter target = new StringWriter();
570
                StringWriter target = new StringWriter();
557
571
Lines 568-593 Link Here
568
        return result;
582
        return result;
569
    }
583
    }
570
584
571
    private static String template(CompilationUnitTree cut) {
585
    String template(ElementKind kind) {
572
        if ("package-info.java".equals(cut.getSourceFile().getName())) return "Templates/Classes/package-info.java";
586
        if(kind == null) {
573
        if (cut.getTypeDecls().isEmpty()) return "Templates/Classes/Empty.java";
587
            return "Templates/Classes/Empty.java"; // NOI18N
574
588
        }
575
        switch (cut.getTypeDecls().get(0).getKind()) {
589
        switch (kind) {
576
            case CLASS: return "Templates/Classes/Class.java"; // NOI18N
590
            case CLASS: return "Templates/Classes/Class.java"; // NOI18N
577
            case INTERFACE: return "Templates/Classes/Interface.java"; // NOI18N
591
            case INTERFACE: return "Templates/Classes/Interface.java"; // NOI18N
578
            case ANNOTATION_TYPE: return "Templates/Classes/AnnotationType.java"; // NOI18N
592
            case ANNOTATION_TYPE: return "Templates/Classes/AnnotationType.java"; // NOI18N
579
            case ENUM: return "Templates/Classes/Enum.java"; // NOI18N
593
            case ENUM: return "Templates/Classes/Enum.java"; // NOI18N
594
            case PACKAGE: return "Templates/Classes/package-info.java"; // NOI18N
580
            default:
595
            default:
581
                Logger.getLogger(WorkingCopy.class.getName()).log(Level.SEVERE, "Cannot resolve template for {0}", cut.getTypeDecls().get(0).getKind());
596
                Logger.getLogger(WorkingCopy.class.getName()).log(Level.SEVERE, "Cannot resolve template for {0}", kind);
582
                return "Templates/Classes/Empty.java";
597
                return "Templates/Classes/Empty.java"; // NOI18N
583
        }
598
        }
584
    }
599
    }
585
600
586
    private static FileObject doCreateFromTemplate(CompilationUnitTree t) throws IOException {
601
    FileObject doCreateFromTemplate(CompilationUnitTree cut) throws IOException {
602
        ElementKind kind;
603
        if ("package-info.java".equals(cut.getSourceFile().getName())) {
604
            kind = ElementKind.PACKAGE;
605
        } else if (cut.getTypeDecls().isEmpty()) {
606
            kind = null;
607
        } else {
608
            switch (cut.getTypeDecls().get(0).getKind()) {
609
                case CLASS:
610
                    kind = ElementKind.CLASS;
611
                    break;
612
                case INTERFACE:
613
                    kind = ElementKind.INTERFACE;
614
                    break;
615
                case ANNOTATION_TYPE:
616
                    kind = ElementKind.ANNOTATION_TYPE;
617
                    break;
618
                case ENUM:
619
                    kind = ElementKind.ENUM;
620
                    break;
621
                default:
622
                    Logger.getLogger(WorkingCopy.class.getName()).log(Level.SEVERE, "Cannot resolve template for {0}", cut.getTypeDecls().get(0).getKind());
623
                    kind = null;
624
            }
625
        }
626
        FileObject template = FileUtil.getConfigFile(template(kind));
627
        return doCreateFromTemplate(template, cut.getSourceFile());
628
    }
629
630
    FileObject doCreateFromTemplate(FileObject template, JavaFileObject sourceFile) throws IOException {
587
        FileObject scratchFolder = FileUtil.createMemoryFileSystem().getRoot();
631
        FileObject scratchFolder = FileUtil.createMemoryFileSystem().getRoot();
588
632
589
        FileObject template = FileUtil.getConfigFile(template(t));
590
591
        if (template == null) {
633
        if (template == null) {
592
            return scratchFolder.createData("out", "java");
634
            return scratchFolder.createData("out", "java");
593
        }
635
        }
Lines 598-604 Link Here
598
            return scratchFolder.createData("out", "java");
640
            return scratchFolder.createData("out", "java");
599
        }
641
        }
600
642
601
        File pack = new File(t.getSourceFile().toUri()).getParentFile();
643
        File pack = new File(sourceFile.toUri()).getParentFile();
602
644
603
        while (FileUtil.toFileObject(pack) == null) {
645
        while (FileUtil.toFileObject(pack) == null) {
604
            pack = pack.getParentFile();
646
            pack = pack.getParentFile();
(-)a/java.source/src/org/netbeans/modules/java/source/parsing/FileObjects.java (+4 lines)
Lines 1056-1061 Link Here
1056
            assert parentFo != null;
1056
            assert parentFo != null;
1057
            DataFolder target = DataFolder.findFolder(parentFo);
1057
            DataFolder target = DataFolder.findFolder(parentFo);
1058
            FileObject template = FileUtil.getConfigFile("Templates/Classes/Empty.java");     //NOI18N
1058
            FileObject template = FileUtil.getConfigFile("Templates/Classes/Empty.java");     //NOI18N
1059
            if(template == null) {
1060
                FileUtil.createData(parentFo, f.getName());
1061
                return;
1062
            }
1059
            DataObject templateDobj = DataObject.find(template);
1063
            DataObject templateDobj = DataObject.find(template);
1060
            String simpleName = FileObjects.stripExtension(f.getName());
1064
            String simpleName = FileObjects.stripExtension(f.getName());
1061
            DataObject newDobj = templateDobj.createFromTemplate(target, simpleName);
1065
            DataObject newDobj = templateDobj.createFromTemplate(target, simpleName);
(-)a/java.source/test/unit/src/org/netbeans/api/java/source/gen/CompilationUnitTest.java (-2 / +145 lines)
Lines 39-44 Link Here
39
import java.util.Collections;
39
import java.util.Collections;
40
import java.util.EnumSet;
40
import java.util.EnumSet;
41
import java.util.Map;
41
import java.util.Map;
42
import javax.lang.model.element.ElementKind;
42
import javax.lang.model.element.Modifier;
43
import javax.lang.model.element.Modifier;
43
import javax.lang.model.element.TypeElement;
44
import javax.lang.model.element.TypeElement;
44
import javax.lang.model.type.TypeKind;
45
import javax.lang.model.type.TypeKind;
Lines 85-93 Link Here
85
    @Override
86
    @Override
86
    protected void setUp() throws Exception {
87
    protected void setUp() throws Exception {
87
        super.setUp();
88
        super.setUp();
88
        FileObject templates = FileUtil.getConfigFile("Templates/Classes/Class.java");
89
        FileObject template = FileUtil.getConfigFile("Templates/Classes/Class.java");
90
        if (template != null) template.delete();
91
        FileObject template2 = FileUtil.getConfigFile("Templates/Classes/package-info.java");
92
        if (template2 != null) template2.delete();
93
    }
89
94
90
        if (templates != null) templates.delete();
95
    public void testNewCompilationUnitFromTemplate() throws Exception {
96
        testFile = new File(getWorkDir(), "Test.java");
97
98
        File fakeFile = new File(getWorkDir(), "Fake.java");
99
        FileObject fakeFO = FileUtil.createData(fakeFile);
100
101
        FileObject emptyJava = FileUtil.createData(FileUtil.getConfigRoot(), "Templates/Classes/Empty.java");
102
        emptyJava.setAttribute("template", Boolean.TRUE);
103
104
        FileObject classJava = FileUtil.createData(FileUtil.getConfigRoot(), "Templates/Classes/Class.java");
105
        classJava.setAttribute("template", Boolean.TRUE);
106
        classJava.setAttribute("verbatim-create-from-template", Boolean.TRUE);
107
        Writer w = new OutputStreamWriter(classJava.getOutputStream(), "UTF-8");
108
        w.write("/*\n * License\n */\npackage zoo;\n\n/**\n * trida\n */\npublic class Template {\n}");
109
        w.close();
110
111
        FileObject packageJava = FileUtil.createData(FileUtil.getConfigRoot(), "Templates/Classes/package-info.java");
112
        packageJava.setAttribute("template", Boolean.TRUE);
113
        packageJava.setAttribute("verbatim-create-from-template", Boolean.TRUE);
114
        Writer w2 = new OutputStreamWriter(packageJava.getOutputStream(), "UTF-8");
115
        w2.write("/*\n * License\n */\npackage zoo;\n");
116
        w2.close();
117
118
        FileObject testSourceFO = FileUtil.createData(testFile); assertNotNull(testSourceFO);
119
        ClassPath sourcePath = ClassPath.getClassPath(testSourceFO, ClassPath.SOURCE); assertNotNull(sourcePath);
120
        FileObject[] roots = sourcePath.getRoots(); assertEquals(1, roots.length);
121
        final FileObject sourceRoot = roots[0]; assertNotNull(sourceRoot);
122
        ClassPath compilePath = ClassPath.getClassPath(testSourceFO, ClassPath.COMPILE); assertNotNull(compilePath);
123
        ClassPath bootPath = ClassPath.getClassPath(testSourceFO, ClassPath.BOOT); assertNotNull(bootPath);
124
        ClasspathInfo cpInfo = ClasspathInfo.create(bootPath, compilePath, sourcePath);
125
        JavaSource javaSource = JavaSource.create(cpInfo, fakeFO);
126
127
        Task<WorkingCopy> task = new Task<WorkingCopy>() {
128
129
            public void cancel() {
130
            }
131
132
            public void run(WorkingCopy workingCopy) throws Exception {
133
                workingCopy.toPhase(JavaSource.Phase.PARSED);
134
                TreeMaker make = workingCopy.getTreeMaker();
135
                String path = "zoo/Krtek.java";
136
                GeneratorUtilities genUtils = GeneratorUtilities.get(workingCopy);
137
                CompilationUnitTree newTree = genUtils.createFromTemplate(sourceRoot, path, ElementKind.CLASS);
138
                MethodTree nju = make.Method(
139
                        make.Modifiers(Collections.<Modifier>emptySet()),
140
                        "m",
141
                        make.PrimitiveType(TypeKind.VOID), // return type - void
142
                        Collections.<TypeParameterTree>emptyList(),
143
                        Collections.<VariableTree>emptyList(),
144
                        Collections.<ExpressionTree>emptyList(),
145
                        make.Block(Collections.<StatementTree>emptyList(), false),
146
                        null // default value - not applicable
147
                );
148
                ClassTree clazz = make.Class(
149
                        make.Modifiers(Collections.<Modifier>singleton(Modifier.PUBLIC)),
150
                        "Krtek",
151
                        Collections.<TypeParameterTree>emptyList(),
152
                        null,
153
                        Collections.<Tree>emptyList(),
154
                        Collections.singletonList(nju)
155
                );
156
                if(newTree.getTypeDecls().isEmpty()) {
157
                    newTree = make.addCompUnitTypeDecl(newTree, clazz);
158
                } else {
159
                    Tree templateClass = newTree.getTypeDecls().get(0);
160
                    genUtils.copyComments(templateClass, clazz, true);
161
                    genUtils.copyComments(templateClass, clazz, false);
162
                    newTree = make.removeCompUnitTypeDecl(newTree, 0);
163
                    newTree = make.insertCompUnitTypeDecl(newTree, 0, clazz);
164
                }
165
                workingCopy.rewrite(null, newTree);
166
167
                String packagePath = "zoo/package-info.java";
168
                CompilationUnitTree newPackageTree = genUtils.createFromTemplate(sourceRoot, packagePath, ElementKind.PACKAGE);
169
                workingCopy.rewrite(null, newPackageTree);
170
            }
171
        };
172
        ModificationResult result = javaSource.runModificationTask(task);
173
        result.commit();
174
175
        String goldenClass =
176
            "/*\n * License\n */\n" +
177
            "package zoo;\n" +
178
            "\n" +
179
            "/**\n * trida\n */\n" +
180
            "public class Krtek {\n" +
181
            "\n" +
182
            "    void m() {\n" +
183
            "    }\n" +
184
            "}";
185
        String res = TestUtilities.copyFileToString(new File(getDataDir().getAbsolutePath() + "/zoo/Krtek.java"));
186
        assertEquals(goldenClass, res);
187
188
        String goldenPackage =
189
            "/*\n * License\n */\n" +
190
            "package zoo;\n";
191
        res = TestUtilities.copyFileToString(new File(getDataDir().getAbsolutePath() + "/zoo/package-info.java"));
192
        assertEquals(goldenPackage, res);
193
    }
194
195
    public void testNewCompilationUnitFromNonExistingTemplate() throws Exception {
196
        testFile = new File(getWorkDir(), "Test.java");
197
198
        File fakeFile = new File(getWorkDir(), "Fake.java");
199
        FileObject fakeFO = FileUtil.createData(fakeFile);
200
201
        FileObject template = FileUtil.getConfigFile("Templates/Classes/Class.java");
202
        if (template != null) template.delete();
203
        template = FileUtil.getConfigFile("Templates/Classes/Empty.java");
204
        if(template != null) template.delete();
205
206
        FileObject testSourceFO = FileUtil.createData(testFile); assertNotNull(testSourceFO);
207
        ClassPath sourcePath = ClassPath.getClassPath(testSourceFO, ClassPath.SOURCE); assertNotNull(sourcePath);
208
        FileObject[] roots = sourcePath.getRoots(); assertEquals(1, roots.length);
209
        final FileObject sourceRoot = roots[0]; assertNotNull(sourceRoot);
210
        ClassPath compilePath = ClassPath.getClassPath(testSourceFO, ClassPath.COMPILE); assertNotNull(compilePath);
211
        ClassPath bootPath = ClassPath.getClassPath(testSourceFO, ClassPath.BOOT); assertNotNull(bootPath);
212
        ClasspathInfo cpInfo = ClasspathInfo.create(bootPath, compilePath, sourcePath);
213
        JavaSource javaSource = JavaSource.create(cpInfo, fakeFO);
214
215
        Task<WorkingCopy> task = new Task<WorkingCopy>() {
216
217
            public void cancel() {
218
            }
219
220
            public void run(WorkingCopy workingCopy) throws Exception {
221
                workingCopy.toPhase(JavaSource.Phase.PARSED);
222
                TreeMaker make = workingCopy.getTreeMaker();
223
                String path = "zoo/Krtek.java";
224
                GeneratorUtilities genUtils = GeneratorUtilities.get(workingCopy);
225
                CompilationUnitTree newTree = genUtils.createFromTemplate(sourceRoot, path, ElementKind.CLASS);
226
                workingCopy.rewrite(null, newTree);
227
            }
228
        };
229
        ModificationResult result = javaSource.runModificationTask(task);
230
        result.commit();
231
232
        String res = TestUtilities.copyFileToString(new File(getDataDir().getAbsolutePath() + "/zoo/Krtek.java"));
233
        assertEquals(res, "package zoo;\n\n");
91
    }
234
    }
92
235
93
    public void testNewCompilationUnit() throws Exception {
236
    public void testNewCompilationUnit() throws Exception {

Return to bug 209798