001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2014  Oliver Burn
004//
005// This library is free software; you can redistribute it and/or
006// modify it under the terms of the GNU Lesser General Public
007// License as published by the Free Software Foundation; either
008// version 2.1 of the License, or (at your option) any later version.
009//
010// This library is distributed in the hope that it will be useful,
011// but WITHOUT ANY WARRANTY; without even the implied warranty of
012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013// Lesser General Public License for more details.
014//
015// You should have received a copy of the GNU Lesser General Public
016// License along with this library; if not, write to the Free Software
017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
018////////////////////////////////////////////////////////////////////////////////
019
020package com.puppycrawl.tools.checkstyle.checks.imports;
021
022import java.util.ArrayList;
023import java.util.List;
024import java.util.StringTokenizer;
025import java.util.regex.Pattern;
026
027import com.puppycrawl.tools.checkstyle.api.Check;
028import com.puppycrawl.tools.checkstyle.api.DetailAST;
029import com.puppycrawl.tools.checkstyle.api.FullIdent;
030import com.puppycrawl.tools.checkstyle.api.TokenTypes;
031import com.puppycrawl.tools.checkstyle.api.Utils;
032
033/**
034 * <p>
035 * Checks that the groups of import declarations appear in the order specified
036 * by the user. If there is an import but its group is not specified in the
037 * configuration such an import should be placed at the end of the import list.
038 * </p>
039 * The rule consists of:
040 *
041 * <pre>
042 * STATIC group. This group sets the ordering of static imports.
043 * </pre>
044 *
045 * <pre>
046 * SAME_PACKAGE(n) group. This group sets the ordering of the same package imports.
047 * 'n' - a number of the first package domains. For example:
048 * </pre>
049 *
050 * <pre>
051 * <code>
052 * package java.util.concurrent;
053 *
054 * import java.util.regex.Pattern;
055 * import java.util.List;
056 * import java.util.StringTokenizer;
057 * import java.util.regex.Pattern;
058 * import java.util.*;
059 * import java.util.concurrent.AbstractExecutorService;
060 * import java.util.concurrent.*;
061 *
062 * And we have such configuration: SAME_PACKAGE (3).
063 * Same package imports are java.util.*, java.util.concurrent.*,
064 * java.util.concurrent.AbstractExecutorService,
065 * java.util.List and java.util.StringTokenizer
066 * </code>
067 * </pre>
068 *
069 * <pre>
070 * THIRD_PARTY_PACKAGE group. This group sets ordering of third party imports.
071 * Third party imports are all imports except STATIC,
072 * SAME_PACKAGE(n), STANDARD_JAVA_PACKAGE and SPECIAL_IMPORTS.
073 * </pre>
074 *
075 * <pre>
076 * STANDARD_JAVA_PACKAGE group. This group sets ordering of standard java (java|javax) imports.
077 * </pre>
078 *
079 * <pre>
080 * SPECIAL_IMPORTS group. This group may contains some imports
081 * that have particular meaning for the user.
082 * </pre>
083 *
084 * <p>
085 * NOTICE!
086 * </p>
087 * <p>
088 * Use the separator '###' between rules.
089 * </p>
090 * <p>
091 * To set RegExps for THIRD_PARTY_PACKAGE and STANDARD_JAVA_PACKAGE groups use
092 * thirdPartyPackageRegExp and standardPackageRegExp options.
093 * </p>
094 *
095 * <pre>
096 * For example:
097 * </pre>
098 *
099 * <pre>
100 * <code>
101 * &lt;module name=&quot;CustomImportOrder&quot;&gt;
102 *    &lt;property name=&quot;customImportOrderRules&quot;
103 *    value=&quot;STATIC###SAME_PACKAGE(3)###THIRD_PARTY_PACKAGE###STANDARD_JAVA_PACKAGE&quot;/&gt;
104 *    &lt;property name=&quot;thirdPartyPackageRegExp&quot; value=&quot;com|org&quot;/&gt;
105 *    &lt;property name=&quot;standardPackageRegExp&quot; value=&quot;java|javax&quot;/&gt;
106 * &lt;/module&gt;
107 * </code>
108 * </pre>
109 * <p>
110 * Also, this check can be configured to force empty line separator between
111 * import groups. For example
112 * </p>
113 *
114 * <pre>
115 * <code>
116 * &lt;module name=&quot;CustomImportOrder&quot;&gt;
117 *    &lt;property name=&quot;separateLineBetweenGroups&quot; value=&quot;true&quot;/&gt;
118 * &lt;/module&gt;
119 * </code>
120 * </pre>
121 * <p>
122 * By the option it is possible to force alphabetically sorting.
123 * </p>
124 *
125 * <pre>
126 * <code>
127 * &lt;module name=&quot;CustomImportOrder&quot;&gt;
128 *    &lt;property name=&quot;sortImportsInGroupAlphabetically&quot; value=&quot;true&quot;/&gt;
129 * &lt;/module&gt;
130 * </code>
131 * </pre>
132 *
133 * <p>
134 * To force checking imports sequence such as:
135 * </p>
136 *
137 * <pre>
138 * <code>
139 * package com.puppycrawl.tools.checkstyle.imports;
140 *
141 * import com.google.common.annotations.GwtCompatible;
142 * import com.google.common.annotations.Beta;
143 * import com.google.common.annotations.VisibleForTesting;
144 *
145 * import org.abego.treelayout.Configuration;
146 *
147 * import static sun.tools.util.ModifierFilter.ALL_ACCESS;
148 *
149 * import com.google.common.annotations.GwtCompatible; // violation here - should be in the
150 *                                                     // THIRD_PARTY_PACKAGE group
151 * import android.*;</code>
152 * </pre>
153 * configure as follows:
154 * <pre>
155 * <code>
156 * &lt;module name=&quot;CustomImportOrder&quot;&gt;
157 *    &lt;property name=&quot;customImportOrderRules&quot;
158 *    value=&quot;SAME_PACKAGE(3)###THIRD_PARTY_PACKAGE###STATIC###SPECIAL_IMPORTS&quot;/&gt;
159 *    &lt;property name=&quot;specialImportsRegExp&quot; value=&quot;android.*&quot;/&gt;
160 * &lt;/module&gt;</code>
161 * </pre>
162 *
163 * @author maxvetrenko
164 * @author <a href="mailto:nesterenko-aleksey@list.ru">Aleksey Nesterenko</a>
165 */
166public class CustomImportOrderCheck extends Check
167{
168
169    /** STATIC group name */
170    private static final String STATIC_RULE_GROUP = "STATIC";
171
172    /** SAME_PACKAGE group name */
173    private static final String SAME_PACKAGE_RULE_GROUP = "SAME_PACKAGE";
174
175    /** THIRD_PARTY_PACKAGE group name */
176    private static final String THIRD_PARTY_PACKAGE_RULE_GROUP = "THIRD_PARTY_PACKAGE";
177
178    /** STANDARD_JAVA_PACKAGE group name */
179    private static final String STANDARD_JAVA_PACKAGE_RULE_GROUP = "STANDARD_JAVA_PACKAGE";
180
181    /** NON_GROUP group name */
182    private static final String SPECIAL_IMPORTS_RULE_GROUP = "SPECIAL_IMPORTS";
183
184    /** NON_GROUP group name */
185    private static final String NON_GROUP_RULE_GROUP = "NON_GROUP";
186
187    /** RegExp for SAME_PACKAGE group imports */
188    private String samePackageDomainsRegExp = "";
189
190    /** RegExp for STANDARD_JAVA_PACKAGE group imports */
191    private Pattern standardPackageRegExp = Utils.getPattern("java|javax");
192
193    /** RegExp for THIRDPARTY_PACKAGE group imports */
194    private Pattern thirdPartyPackageRegExp = Utils.getPattern(".*");
195
196    /** RegExp for SPECIAL_IMPORTS group imports */
197    private Pattern specialImportsRegExp = Utils.getPattern("^$");
198
199    /** Force empty line separator between import groups */
200    private boolean separateLineBetweenGroups = true;
201
202    /** Force grouping alphabetically */
203    private boolean sortImportsInGroupAlphabetically;
204
205    /** List of order declaration customizing by user */
206    private final List<String> customImportOrderRules =
207            new ArrayList<String>();
208
209    /** Number of first domains for SAME_PACKAGE group. */
210    private int samePackageMatchingDepth = 2;
211
212    /** Contains objects with import attributes */
213    private List<ImportDetails> importToGroupList =
214            new ArrayList<CustomImportOrderCheck.ImportDetails>();
215
216    /**
217     * Sets standardRegExp specified by user.
218     * @param regexp
219     *        user value.
220     */
221    public final void setStandardPackageRegExp(String regexp)
222    {
223        standardPackageRegExp = Utils.getPattern(regexp);
224    }
225
226    /**
227     * Sets thirdPartyRegExp specified by user.
228     * @param regexp
229     *        user value.
230     */
231    public final void setThirdPartyPackageRegExp(String regexp)
232    {
233        thirdPartyPackageRegExp = Utils.getPattern(regexp);
234    }
235
236    /**
237     * Sets specialImportsRegExp specified by user.
238     * @param regexp
239     *        user value.
240     */
241    public final void setSpecialImportsRegExp(String regexp)
242    {
243        specialImportsRegExp = Utils.getPattern(regexp);
244    }
245
246    /**
247     * Sets separateLineBetweenGroups specified by user.
248     * @param value
249     *        user value.
250     */
251    public final void setSeparateLineBetweenGroups(boolean value)
252    {
253        separateLineBetweenGroups = value;
254    }
255
256    /**
257     * Sets sortImportsInGroupAlphabetically specified by user.
258     * @param value
259     *        user value.
260     */
261    public final void setSortImportsInGroupAlphabetically(boolean value)
262    {
263        sortImportsInGroupAlphabetically = value;
264    }
265
266    /**
267     * Sets a custom import order from the rules in the string format specified
268     * by user.
269     * @param inputCustoimportOrder
270     *        user value.
271     */
272    public final void setCustomImportOrderRules(final String inputCustoimportOrder)
273    {
274        customImportOrderRules.clear();
275        try {
276            for (String currentState : inputCustoimportOrder
277                    .split("\\s*###\\s*"))
278            {
279                addRuleastoList(currentState);
280            }
281            customImportOrderRules.add(NON_GROUP_RULE_GROUP);
282        }
283        catch (StringIndexOutOfBoundsException exp) {
284            //if the structure of the input rule isn't correct
285            throw new RuntimeException("Unable to parse input rule: " + exp);
286        }
287    }
288
289    @Override
290    public int[] getDefaultTokens()
291    {
292        return new int[] {
293            TokenTypes.IMPORT,
294            TokenTypes.STATIC_IMPORT,
295            TokenTypes.PACKAGE_DEF,
296        };
297    }
298
299    @Override
300    public void beginTree(DetailAST rootAST)
301    {
302        importToGroupList.clear();
303    }
304
305    @Override
306    public void visitToken(DetailAST ast)
307    {
308        if (ast.getType() == TokenTypes.PACKAGE_DEF) {
309            if (customImportOrderRules.contains(SAME_PACKAGE_RULE_GROUP)
310                    && samePackageMatchingDepth != -1)
311            {
312                samePackageDomainsRegExp = createSamePackageRegexp(
313                        samePackageMatchingDepth, ast);
314            }
315        }
316        else {
317            final String importFullPath = getFullImportIdent(ast);
318            final int lineNo = ast.getLineNo();
319            final boolean isStatic = ast.getType() == TokenTypes.STATIC_IMPORT;
320            importToGroupList.add(new ImportDetails(importFullPath,
321                    lineNo, getImportGroup(isStatic, importFullPath),
322                    isStatic));
323        }
324    }
325
326    @Override
327    public void finishTree(DetailAST rootAST)
328    {
329
330        if (importToGroupList.isEmpty()) {
331            return;
332        }
333
334        final ImportDetails firstImport = importToGroupList.get(0);
335        String currentGroup = getImportGroup(firstImport.isStatic(),
336                firstImport.getImportFullPath());
337        int groupNumber = customImportOrderRules.indexOf(currentGroup);
338        String previousImport = null;
339
340        for (ImportDetails importObject : importToGroupList) {
341            final String importGroup = importObject.getImportGroup();
342            final String fullImportIdent = importObject.importFullPath;
343
344            if (!importGroup.equals(currentGroup)) {
345                if (customImportOrderRules.size() > groupNumber + 1) {
346                    final String nextGroup = getNextImportGroup(groupNumber + 1);
347                    if (importGroup.equals(nextGroup)) {
348                        if (separateLineBetweenGroups && previousImport != null
349                                && !hasEmptyLineBefore(importObject.getLineNumber()))
350                        {
351                            log(importObject.getLineNumber(), "custom.import.order.line.separator",
352                                    fullImportIdent);
353                        }
354                        currentGroup = nextGroup;
355                        groupNumber = customImportOrderRules.indexOf(nextGroup);
356                    }
357                    else {
358                        logWrongImportGroupOrder(importObject.getLineNumber(),
359                                importGroup);
360                    }
361                }
362                else {
363                    logWrongImportGroupOrder(importObject.getLineNumber(),
364                            importGroup);
365                }
366            }
367            else if (sortImportsInGroupAlphabetically
368                    && previousImport != null
369                    && matchesImportGroup(importObject.isStatic(),
370                            fullImportIdent, currentGroup)
371                    && !(compareImports(fullImportIdent, previousImport) >= 0))
372            {
373                log(importObject.getLineNumber(), "custom.import.order.lex", fullImportIdent);
374            }
375            previousImport = fullImportIdent;
376        }
377    }
378
379    /**
380     * Log wrong import group order.
381     * @param currentImportLine
382     *        line number of current import current import.
383     * @param importGroup
384     *        import group.
385     */
386    private void logWrongImportGroupOrder(int currentImportLine, String importGroup)
387    {
388        if (NON_GROUP_RULE_GROUP.equals(importGroup)) {
389            log(currentImportLine, "custom.import.order.nongroup.import");
390        }
391        else {
392            log(currentImportLine, "custom.import.order", importGroup);
393        }
394    }
395
396    /**
397     * Get next import group.
398     * @param currentGroupNumber
399     *        current group number.
400     * @return
401     *        next import group.
402     */
403    private String getNextImportGroup(int currentGroupNumber)
404    {
405        int nextGroupNumber = currentGroupNumber;
406
407        while (customImportOrderRules.size() > nextGroupNumber + 1) {
408            if (hasAnyImportInCurrentGroup(customImportOrderRules.get(nextGroupNumber)))
409            {
410                break;
411            }
412            nextGroupNumber++;
413        }
414        return customImportOrderRules.get(nextGroupNumber);
415    }
416
417    /**
418     * Checks if current group contains any import.
419     * @param currentGroup
420     *        current group.
421     * @return
422     *        true, if current group contains at least one import.
423     */
424    private boolean hasAnyImportInCurrentGroup(String currentGroup)
425    {
426        for (ImportDetails currentImport : importToGroupList) {
427            if (currentGroup.equals(currentImport.getImportGroup())) {
428                return true;
429            }
430        }
431        return false;
432    }
433
434    /**
435     * Get import valid group.
436     * @param isStatic
437     *        is static import.
438     * @param importPath
439     *        full import path.
440     * @return import valid group.
441     */
442    private String getImportGroup(boolean isStatic, String importPath)
443    {
444        for (String group : customImportOrderRules) {
445            if (matchesImportGroup(isStatic, importPath, group)) {
446                return group;
447            }
448        }
449        return NON_GROUP_RULE_GROUP;
450    }
451
452    /**
453     * Checks if the import is placed in the correct group.
454     * @param isStatic
455     *        if import is static.
456     * @param importPath
457     *        import full path.
458     * @param currentGroup
459     *        current group.
460     * @return true, if import placed in the correct group.
461     */
462    private boolean matchesImportGroup(boolean isStatic, String importPath, String currentGroup)
463    {
464        return matchesStaticImportGroup(isStatic, currentGroup)
465                || matchesSamePackageImportGroup(isStatic, importPath, currentGroup)
466                || matchesSpecialImportsGroup(isStatic, importPath, currentGroup)
467                || matchesStandartImportGroup(isStatic, importPath, currentGroup)
468                || matchesThirdPartyImportGroup(isStatic, importPath, currentGroup);
469    }
470
471    /**
472     * Checks if the import is placed in the STATIC group.
473     * @param isStatic
474     *        is static import.
475     * @param currentGroup
476     *        current group.
477     * @return true, if the import is placed in the static group.
478     */
479    private boolean matchesStaticImportGroup(boolean isStatic, String currentGroup)
480    {
481        return isStatic && STATIC_RULE_GROUP.equals(currentGroup);
482    }
483
484    /**
485     * Checks if the import is placed in the correct group.
486     * @param isStatic
487     *        if import is static.
488     * @param importFullPath
489     *        import full path.
490     * @param currentGroup
491     *        current group.
492     * @return true, if the import is placed in the same package group.
493     */
494    private boolean matchesSamePackageImportGroup(boolean isStatic,
495        String importFullPath, String currentGroup)
496    {
497        final String importPath = importFullPath.substring(0, importFullPath.lastIndexOf("."));
498        return !isStatic && SAME_PACKAGE_RULE_GROUP.equals(currentGroup)
499                && samePackageDomainsRegExp.contains(importPath);
500    }
501
502    /**
503     * Checks if the import is placed in the correct group.
504     * @param isStatic
505     *        if import is static.
506     * @param currentImport
507     *        import full path.
508     * @param currentGroup
509     *        current group.
510     * @return true, if the import is placed in the standard group.
511     */
512    private boolean matchesStandartImportGroup(boolean isStatic,
513        String currentImport, String currentGroup)
514    {
515        return !isStatic && STANDARD_JAVA_PACKAGE_RULE_GROUP.equals(currentGroup)
516                && standardPackageRegExp.matcher(currentImport).find();
517    }
518
519    /**
520     * Checks if the import is placed in the correct group.
521     * @param isStatic
522     *        if import is static.
523     * @param currentImport
524     *        import full path.
525     * @param currentGroup
526     *        current group.
527     * @return true, if the import is placed in the special group.
528     */
529    private boolean matchesSpecialImportsGroup(boolean isStatic,
530        String currentImport, String currentGroup)
531    {
532        return !isStatic && SPECIAL_IMPORTS_RULE_GROUP.equals(currentGroup)
533                && specialImportsRegExp.matcher(currentImport).find();
534    }
535
536    /**
537     * Checks if the import is placed in the correct group.
538     * @param isStatic
539     *        if import is static.
540     * @param currentImport
541     *        import full path.
542     * @param currentGroup
543     *        current group.
544     * @return true, if the import is placed in the third party group.
545     */
546    private boolean matchesThirdPartyImportGroup(boolean isStatic,
547        String currentImport, String currentGroup)
548    {
549        return !isStatic && THIRD_PARTY_PACKAGE_RULE_GROUP.equals(currentGroup)
550                && thirdPartyPackageRegExp.matcher(currentImport).find()
551                && !standardPackageRegExp.matcher(currentImport).find()
552                && !specialImportsRegExp.matcher(currentImport).find();
553    }
554
555    /**
556     * Checks compare two import paths.
557     * @param import1
558     *        current import.
559     * @param import2
560     *        previous import.
561     * @return a negative integer, zero, or a positive integer as the
562     *        specified String is greater than, equal to, or less
563     *        than this String, ignoring case considerations.
564     */
565    private static int compareImports(String import1, String import2)
566    {
567        int result = 0;
568        final String[] import1Tokens = import1.split("\\.");
569        final String[] import2Tokens = import2.split("\\.");
570        for (int i = 0; i < import1Tokens.length; i++) {
571            if (i == import2Tokens.length) {
572                break;
573            }
574            final String import1Token = import1Tokens[i];
575            final String import2Token = import2Tokens[i];
576            result = import1Token.compareToIgnoreCase(import2Token);
577            if (result != 0) {
578                break;
579            }
580        }
581        return result;
582    }
583
584    /**
585     * Return class name from import full path.
586     * @param startFrom number of start.
587     * @param importPath import full path.
588     * @return class name.
589     */
590    private String getClassName(int startFrom, String importPath)
591    {
592        String className = importPath;
593        className = className.substring(startFrom, className.length());
594        final StringTokenizer token = new StringTokenizer(className, ".\r");
595        return token.nextToken();
596    }
597
598    /**
599     * Checks if a token has a empty line before.
600     * @param lineNo
601     *        Line number of current import.
602     * @return true, if token have empty line before.
603     */
604    private boolean hasEmptyLineBefore(int lineNo)
605    {
606        //  [lineNo - 2] is the number of the previous line
607        //  because the numbering starts from zero.
608        final String lineBefore = getLine(lineNo - 2);
609        return lineBefore.trim().isEmpty();
610    }
611
612    /**
613     * Forms import full path.
614     * @param token
615     *        current token.
616     * @return full path or null.
617     */
618    private static String getFullImportIdent(DetailAST token)
619    {
620        return token != null ? FullIdent.createFullIdent(token.
621                findFirstToken(TokenTypes.DOT)).getText() : "";
622    }
623
624    /**
625     * Parses ordering rule and adds it to the list with rules.
626     * @param ruleStr
627     *        String with rule.
628     */
629    private void addRuleastoList(String ruleStr)
630    {
631        if (STATIC_RULE_GROUP.equals(ruleStr)
632                || THIRD_PARTY_PACKAGE_RULE_GROUP.equals(ruleStr)
633                || STANDARD_JAVA_PACKAGE_RULE_GROUP.equals(ruleStr)
634                || SPECIAL_IMPORTS_RULE_GROUP.equals(ruleStr))
635        {
636            customImportOrderRules.add(ruleStr);
637
638        }
639        else if (ruleStr.startsWith(SAME_PACKAGE_RULE_GROUP)) {
640
641            final String rule = ruleStr.substring(ruleStr.indexOf("(") + 1,
642                    ruleStr.indexOf(")"));
643            try {
644                samePackageMatchingDepth = Integer.parseInt(rule);
645            }
646            catch (Exception e) {
647                samePackageDomainsRegExp = rule;
648            }
649            customImportOrderRules.add(SAME_PACKAGE_RULE_GROUP);
650
651        }
652        else {
653            throw new RuntimeException("Unexpected rule: " + ruleStr);
654        }
655    }
656
657    /**
658     * Creates samePackageDomainsRegExp of the first package domains.
659     * @param firstPackageDomainsCount
660     *        number of first package domains.
661     * @param packageNode
662     *        package node.
663     * @return same package regexp.
664     */
665    private static String createSamePackageRegexp(int firstPackageDomainsCount,
666             DetailAST packageNode)
667    {
668        final StringBuilder builder = new StringBuilder();
669        final String packageFullPath = getFullImportIdent(packageNode);
670        final StringTokenizer tokens = new StringTokenizer(packageFullPath, ".");
671        int count = firstPackageDomainsCount;
672
673        while (tokens.hasMoreTokens() && count > 0) {
674            builder.append(tokens.nextToken()).append(".");
675            count--;
676        }
677        return builder.append("*").toString();
678    }
679
680    /**
681     * Contains import attributes as line number, import full path, import
682     * group.
683     * @author max
684     */
685    class ImportDetails
686    {
687        /** Import full path */
688        private String importFullPath;
689
690        /** Import line number */
691        private int lineNumber;
692
693        /** Import group */
694        private String importGroup;
695
696        /** Is static import */
697        private boolean isStatic;
698
699        /**
700         * @param importFullPath
701         *        import full path.
702         * @param lineNumber
703         *        import line number.
704         * @param importGroup
705         *        import group.
706         * @param isStatic
707         *        if import is static.
708         */
709        public ImportDetails(String importFullPath,
710                int lineNumber, String importGroup, boolean isStatic)
711        {
712            setImportFullPath(importFullPath);
713            setLineNumber(lineNumber);
714            setImportGroup(importGroup);
715            setStatic(isStatic);
716        }
717
718        /**
719         * Get import full path variable.
720         * @return import full path variable.
721         */
722        public String getImportFullPath()
723        {
724            return importFullPath;
725        }
726
727        /**
728         * Set import full path variable.
729         * @param importFullPath
730         *        import full path variable.
731         */
732        public void setImportFullPath(String importFullPath)
733        {
734            this.importFullPath = importFullPath;
735        }
736
737        /**
738         * Get import line number.
739         * @return import line.
740         */
741        public int getLineNumber()
742        {
743            return lineNumber;
744        }
745
746        /**
747         * Set import line number.
748         * @param lineNumber
749         *        import line number.
750         */
751        public void setLineNumber(int lineNumber)
752        {
753            this.lineNumber = lineNumber;
754        }
755
756        /**
757         * Get import group.
758         * @return import group.
759         */
760        public String getImportGroup()
761        {
762            return importGroup;
763        }
764
765        /**
766         * Set import group.
767         * @param importGroup
768         *        import group.
769         */
770        public void setImportGroup(String importGroup)
771        {
772            this.importGroup = importGroup;
773        }
774
775        /**
776         * Checks if import is static.
777         * @return true, if import is static.
778         */
779        public boolean isStatic()
780        {
781            return isStatic;
782        }
783
784        /**
785         * Set true, if import is static
786         * @param isStatic
787         *        if import is static.
788         */
789        public void setStatic(boolean isStatic)
790        {
791            this.isStatic = isStatic;
792        }
793    }
794}