1   /*
2    * Copyright 2003 - 2013 The eFaps Team
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   * Revision:        $Rev$
17   * Last Changed:    $Date$
18   * Last Changed By: $Author$
19   */
20  
21  package org.efaps.admin.ui;
22  
23  import java.util.ArrayList;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.TreeMap;
27  
28  import org.apache.commons.lang3.builder.ToStringBuilder;
29  import org.efaps.ci.CIAdminUserInterface;
30  import org.efaps.db.Instance;
31  import org.efaps.db.MultiPrintQuery;
32  import org.efaps.db.QueryBuilder;
33  import org.efaps.jaas.AppAccessHandler;
34  import org.efaps.util.EFapsException;
35  import org.efaps.util.cache.CacheReloadException;
36  
37  /**
38   * @author The eFaps Team
39   * @version $Id$
40   */
41  public abstract class AbstractMenu
42      extends AbstractCommand
43  {
44      /**
45       * Needed for serialization.
46       */
47      private static final long serialVersionUID = 1L;
48  
49      /**
50       * All sub commands or menus are store in the tree map. The tree map is used
51       * to sort the commands / menus belonging to their id.
52       *
53       * @see #getCommands
54       * @add
55       */
56      private final Map<Long, AbstractCommand> commands = new TreeMap<Long, AbstractCommand>();
57  
58      /**
59       * Constructor to set the id,uuid and name of the menu object.
60       *
61       * @param _id id of the command to set
62       * @param _uuid UUID of the command to set
63       * @param _name name of the command to set
64       */
65      protected AbstractMenu(final long _id,
66                             final String _uuid,
67                             final String _name)
68      {
69          super(_id, _uuid, _name);
70      }
71  
72      /**
73       * Adds a command or menu to this menu instance. The method must be specific
74       * implemented by all menu implementations.
75       *
76       * @param _sortId id used to sort
77       * @param _id id of the sub command / menu to add
78       * @throws CacheReloadException on error
79       */
80      protected abstract void add(final long _sortId,
81                                  final long _id)
82          throws CacheReloadException;
83  
84      /**
85       * Add a command to the menu structure.
86       *
87       * @param _sortId id used to sort
88       * @param _command command to add
89       */
90      public void add(final long _sortId,
91                      final AbstractCommand _command)
92      {
93          this.commands.put(_sortId, _command);
94      }
95  
96      /**
97       * Add all sub commands and menus of the given menu to this menu structure.
98       *
99       * @param _menu menu with sub structure
100      */
101     public void addAll(final AbstractMenu _menu)
102     {
103         this.commands.putAll(_menu.commands);
104     }
105 
106     /**
107      * Check, if the user of the context has access to this user interface
108      * object. First, the instance method checks, if some access configuration
109      * exists for this menu instance object. If the user has access for this
110      * menu, it is test, if the context user has access to minimum one sub
111      * command command / menu. If yes, the user is allowed to access this menu
112      * instance, other the user is not allowed to access this menu.
113      *
114      * @param _targetMode TargetMode of the Command
115      * @param _instance the field will represent, e.g. on edit mode
116      * @return <i>true</i>if context user has access, otherwise <i>false</i> is
117      *         returned
118      * @throws EFapsException on error
119      */
120     @Override
121     public boolean hasAccess(final TargetMode _targetMode,
122                              final Instance _instance)
123         throws EFapsException
124     {
125         boolean ret = super.hasAccess(_targetMode, _instance);
126 
127         if (ret && getCommands().size() > 0 && !AppAccessHandler.excludeMode()) {
128             ret = false;
129             for (final AbstractCommand cmd : getCommands()) {
130                 if (cmd.hasAccess(_targetMode, _instance)) {
131                     ret = true;
132                     break;
133                 }
134             }
135         }
136         return ret;
137     }
138 
139     /**
140      * Returns all information from the menu as string.
141      *
142      * @return String representation of this AbstractMenu
143      */
144     @Override
145     public String toString()
146     {
147         final ToStringBuilder buf = new ToStringBuilder(this).appendSuper(super.toString());
148 
149         for (final AbstractCommand cmd : getCommands()) {
150             buf.append(" ").append(cmd);
151         }
152         return buf.toString();
153     }
154 
155     /**
156      * The method takes values of the {@link #commands} and returnes them as
157      * {@link java.util.ArrayList}.
158      *
159      * @return the values of the {@link #commands} map instance as array list
160      * @see #commands
161      * @see #add(Command)
162      * @see #add(Menu)
163      */
164     public List<AbstractCommand> getCommands()
165     {
166         return new ArrayList<AbstractCommand>(this.commands.values());
167     }
168 
169     /**
170      * The instance method reads all needed information for this user interface
171      * object. The method extends the original method, because the sub menus and
172      * commands must be read.
173      *
174      * @see #readFromDB4Childs
175      * @throws CacheReloadException on error during load
176      */
177     @Override
178     protected void readFromDB()
179         throws CacheReloadException
180     {
181         super.readFromDB();
182         readFromDB4Childs();
183     }
184 
185     /**
186      * The instance method gets all sub menus and commands and adds them to this
187      * menu instance via method {@link #add(long)}.
188      *
189      * @see #readFromDB
190      * @see #add(long)
191      * @throws CacheReloadException on error during load
192      */
193     private void readFromDB4Childs()
194         throws CacheReloadException
195     {
196         try {
197             final QueryBuilder queryBldr = new QueryBuilder(CIAdminUserInterface.Menu2Command);
198             queryBldr.addWhereAttrEqValue(CIAdminUserInterface.Menu2Command.FromMenu, getId());
199             final MultiPrintQuery multi = queryBldr.getPrint();
200             multi.addAttribute(CIAdminUserInterface.Menu2Command.ToCommand);
201             multi.executeWithoutAccessCheck();
202 
203             while (multi.next()) {
204                 final long commandId = multi.<Long> getAttribute(CIAdminUserInterface.Menu2Command.ToCommand);
205                 add(multi.getCurrentInstance().getId(), commandId);
206             }
207         } catch (final EFapsException e) {
208             throw new CacheReloadException("could not read childs for menu '" + getName() + "'", e);
209         }
210     }
211 
212     @Override
213     public boolean equals(final Object _obj)
214     {
215         boolean ret;
216         if (_obj instanceof AbstractMenu) {
217             ret = ((AbstractMenu) _obj).getId() == getId();
218         } else {
219             ret = super.equals(_obj);
220         }
221         return ret;
222     }
223 
224     @Override
225     public int hashCode()
226     {
227         return  Long.valueOf(getId()).intValue();
228     }
229 }