001/*
002 *  Copyright 2018 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.core.impl.right;
017
018import java.util.Arrays;
019import java.util.Collections;
020import java.util.HashMap;
021import java.util.HashSet;
022import java.util.List;
023import java.util.Map;
024import java.util.Optional;
025import java.util.Set;
026import java.util.stream.Collectors;
027
028import org.apache.avalon.framework.configuration.Configuration;
029import org.apache.avalon.framework.configuration.ConfigurationException;
030import org.apache.commons.lang.StringUtils;
031import org.apache.ibatis.session.SqlSession;
032
033import org.ametys.core.datasource.AbstractMyBatisDAO;
034import org.ametys.core.group.GroupIdentity;
035import org.ametys.core.right.ModifiableProfileAssignmentStorage;
036import org.ametys.core.right.ProfileAssignmentStorage;
037import org.ametys.core.user.UserIdentity;
038
039/**
040 * Jdbc implementation of {@link ProfileAssignmentStorage} which stores profile assignments in database.
041 * This only supports String objects as contexts.
042 */
043public class JdbcProfileAssignmentStorage extends AbstractMyBatisDAO implements ModifiableProfileAssignmentStorage
044{
045    
046    /**
047     * The jdbc cache
048     */
049    protected final Map<String, Database> _cache = new HashMap<>();
050    
051    /** The handled context */
052    protected String _supportedContext;
053    
054    @Override
055    public void configure(Configuration configuration) throws ConfigurationException
056    {
057        super.configure(configuration);
058        _supportedContext = configuration.getChild("context").getValue();
059    }
060    
061    /**
062     * Dump the SQL database in an cached object
063     * @param context The context to seek
064     * @return The database
065     */
066    protected Database _getFullData(Object context)
067    {
068        String rootContext = "/" + StringUtils.split((String) context, '/')[0];
069     
070        synchronized (_cache)
071        {
072            if (_cache.containsKey(rootContext))
073            {
074                return _cache.get(rootContext);
075            }
076            
077            try (SqlSession session = getSession())
078            {
079                Map<String, Object> parameters = new HashMap<>();
080                parameters.put("context", rootContext);
081                
082                List<Map<String, String>> profiles = session.selectList("ProfilesAssignment.getAllProfiles", parameters);
083                Database db = new Database(profiles);
084                _cache.put(rootContext, db);
085                
086                return db;
087            }
088        }
089    }
090    
091    /**
092     * Clear the cache of _getFullData
093     */
094    protected void _clearCache()
095    {
096        synchronized (_cache)
097        {
098            _cache.clear();
099        }
100    }
101    
102    /**
103     * Clear the cache of _getFullData
104     * @param context The context to seek
105     */
106    protected void _clearCache(Object context)
107    {
108        String rootContext = "/" + StringUtils.split((String) context, '/')[0];
109        
110        synchronized (_cache)
111        {
112            if (_cache.containsKey(rootContext))
113            {
114                _cache.remove(rootContext);
115            }
116        }
117    }
118    
119    /* -------------- */
120    /* HAS PERMISSION */
121    /* -------------- */
122    
123    /**
124     * Get the object context with prefix if necessary
125     * @param context The context object
126     * @return The prefixed object
127     */
128    protected Object getObjectWithPrefix (Object context)
129    {
130        return context;
131    }
132    
133    /**
134     * Get the prefix for object context 
135     * @return The prefix. Can be null if no prefix is necessary
136     */
137    protected String getPrefix ()
138    {
139        return null;
140    }
141    
142    public boolean hasUserDeniedProfile(Set<? extends Object> rootContexts, UserIdentity user, Set<String> profileIds)
143    {
144        String prefix = getPrefix();
145        Set<String> stringPrefixContexts = rootContexts.stream().filter(String.class::isInstance).map(context -> (prefix != null ? prefix : "") + (String) context).collect(Collectors.toSet());
146        
147        try (SqlSession session = getSession())
148        {
149            Map<String, Object> parameters = new HashMap<>();
150            parameters.put("login", user.getLogin());
151            parameters.put("population", user.getPopulationId());
152            parameters.put("contextPrefixes", stringPrefixContexts);
153            parameters.put("profileIds", profileIds);
154            
155            List<Map<String, String>> deniedProfiles = session.selectList("ProfilesAssignment.getUserDeniedProfiles", parameters);
156            return !deniedProfiles.isEmpty();
157        }
158    }
159    
160    public boolean hasUserAllowedProfile(Set<? extends Object> rootContexts, UserIdentity user, Set<String> profileIds)
161    {
162        String prefix = getPrefix();
163        Set<String> stringPrefixContexts = rootContexts.stream().filter(String.class::isInstance).map(context -> (prefix != null ? prefix : "") + (String) context).collect(Collectors.toSet());
164        
165        try (SqlSession session = getSession())
166        {
167            Map<String, Object> parameters = new HashMap<>();
168            parameters.put("login", user.getLogin());
169            parameters.put("population", user.getPopulationId());
170            parameters.put("contextPrefixes", stringPrefixContexts);
171            parameters.put("profileIds", profileIds);
172            
173            List<Map<String, String>> allowedProfiles = session.selectList("ProfilesAssignment.getUserAllowedProfiles", parameters);
174            return !allowedProfiles.isEmpty();
175        }
176    }
177    
178    public boolean hasGroupDeniedProfile(Set<? extends Object> rootContexts, GroupIdentity group, Set<String> profileIds)
179    {
180        String prefix = getPrefix();
181        Set<String> stringPrefixContexts = rootContexts.stream().filter(String.class::isInstance).map(context -> (prefix != null ? prefix : "") + (String) context).collect(Collectors.toSet());
182        
183        try (SqlSession session = getSession())
184        {
185            Map<String, Object> parameters = new HashMap<>();
186            parameters.put("groupId", group.getId());
187            parameters.put("groupDirectory", group.getDirectoryId());
188            parameters.put("contextPrefixes", stringPrefixContexts);
189            parameters.put("profileIds", profileIds);
190            
191            List<Map<String, String>> deniedProfiles = session.selectList("ProfilesAssignment.getGroupDeniedProfiles", parameters);
192            return !deniedProfiles.isEmpty();
193        }
194    }
195    
196    public boolean hasGroupAllowedProfile(Set<? extends Object> rootContexts, GroupIdentity group, Set<String> profileIds)
197    {
198        String prefix = getPrefix();
199        Set<String> stringPrefixContexts = rootContexts.stream().filter(String.class::isInstance).map(context -> (prefix != null ? prefix : "") + (String) context).collect(Collectors.toSet());
200        
201        try (SqlSession session = getSession())
202        {
203            Map<String, Object> parameters = new HashMap<>();
204            parameters.put("groupId", group.getId());
205            parameters.put("groupDirectory", group.getDirectoryId());
206            parameters.put("contextPrefixes", stringPrefixContexts);
207            parameters.put("profileIds", profileIds);
208            
209            List<Map<String, String>> allowedProfiles = session.selectList("ProfilesAssignment.getGroupAllowedProfiles", parameters);
210            return !allowedProfiles.isEmpty();
211        }
212    }
213    
214    public boolean hasAnyConnectedDeniedProfile(Set<? extends Object> rootContexts, Set<String> profileIds)
215    {
216        String prefix = getPrefix();
217        Set<String> stringPrefixContexts = rootContexts.stream().filter(String.class::isInstance).map(context -> (prefix != null ? prefix : "") + (String) context).collect(Collectors.toSet());
218        
219        try (SqlSession session = getSession())
220        {
221            Map<String, Object> parameters = new HashMap<>();
222            parameters.put("contextPrefixes", stringPrefixContexts);
223            parameters.put("profileIds", profileIds);
224            
225            List<Map<String, String>> deniedProfiles = session.selectList("ProfilesAssignment.getAnyConnectedDeniedProfiles", parameters);
226            return !deniedProfiles.isEmpty();
227        }
228    }
229    
230    public boolean hasAnyConnectedAllowedProfile(Set<? extends Object> rootContexts, Set<String> profileIds)
231    {
232        String prefix = getPrefix();
233        Set<String> stringPrefixContexts = rootContexts.stream().filter(String.class::isInstance).map(context -> (prefix != null ? prefix : "") + (String) context).collect(Collectors.toSet());
234
235        try (SqlSession session = getSession())
236        {
237            Map<String, Object> parameters = new HashMap<>();
238            parameters.put("contextPrefixes", stringPrefixContexts);
239            parameters.put("profileIds", profileIds);
240            
241            List<Map<String, String>> allowedProfiles = session.selectList("ProfilesAssignment.getAnyConnectedAllowedProfiles", parameters);
242            return !allowedProfiles.isEmpty();
243        }
244    }
245    
246    public boolean hasAnonymousDeniedProfile(Set<? extends Object> rootContexts, Set<String> profileIds)
247    {
248        String prefix = getPrefix();
249        Set<String> stringPrefixContexts = rootContexts.stream().filter(String.class::isInstance).map(context -> (prefix != null ? prefix : "") + (String) context).collect(Collectors.toSet());
250        
251        try (SqlSession session = getSession())
252        {
253            Map<String, Object> parameters = new HashMap<>();
254            parameters.put("contextPrefixes", stringPrefixContexts);
255            parameters.put("profileIds", profileIds);
256            
257            List<Map<String, String>> deniedProfiles = session.selectList("ProfilesAssignment.getAnonymousDeniedProfiles", parameters);
258            return !deniedProfiles.isEmpty();
259        }
260    }
261    
262    public boolean hasAnonymousAllowedProfile(Set<? extends Object> rootContexts, Set<String> profileIds)
263    {
264        String prefix = getPrefix();
265        Set<String> stringPrefixContexts = rootContexts.stream().filter(String.class::isInstance).map(context -> (prefix != null ? prefix : "") + (String) context).collect(Collectors.toSet());
266        
267        try (SqlSession session = getSession())
268        {
269            Map<String, Object> parameters = new HashMap<>();
270            parameters.put("contextPrefixes", stringPrefixContexts);
271            parameters.put("profileIds", profileIds);
272            
273            List<Map<String, String>> allowedProfiles = session.selectList("ProfilesAssignment.getAnonymousAllowedProfiles", parameters);
274            return !allowedProfiles.isEmpty();
275        }
276    }
277    
278    /* --------------------------------------- */
279    /* ALLOWED PROFILES FOR ANY CONNECTED USER */
280    /* --------------------------------------- */
281    
282    @Override
283    public Set<String> getAllowedProfilesForAnyConnectedUser(Object object)
284    {
285        return Optional.ofNullable(_getFullData(object).getAllowedAnyConnected().get(object))
286                .orElse(Collections.emptySet());
287    }
288    
289    @Override
290    public boolean isAnyConnectedUserAllowed(Object object, String profileId)
291    {
292        return getAllowedProfilesForAnyConnectedUser(object).contains(profileId);
293    }
294    
295    @Override
296    public void addAllowedProfilesForAnyConnectedUser(Object object, Set<String> profileIds)
297    {
298        _clearCache(object);
299        
300        try (SqlSession session = getSession())
301        {
302            Object prefixedObject = getObjectWithPrefix(object);
303            for (String profileId : profileIds)
304            {
305                Map<String, Object> parameters = new HashMap<>();
306                parameters.put("context", prefixedObject);
307                parameters.put("profileIds", Arrays.asList(profileId));
308                
309                List<Map<String, String>> allowedProfiles = session.selectList("ProfilesAssignment.getAnyConnectedAllowedProfiles", parameters);
310                
311                if (allowedProfiles.isEmpty())
312                {
313                    parameters.put("profileId", profileId);
314                    session.insert("ProfilesAssignment.addAllowedAnyConnected", parameters);
315                }
316                else
317                {
318                    getLogger().debug("Profile {} is already allowed for anyconnected on context {}", profileId, prefixedObject);
319                }
320                
321            }
322            
323            session.commit();
324        }
325    }
326    
327    @Override
328    public void removeAllowedProfilesForAnyConnectedUser(Object object, Set<String> profileIds)
329    {
330        _clearCache(object);
331        
332        try (SqlSession session = getSession(true))
333        {
334            Map<String, Object> parameters = new HashMap<>();
335            parameters.put("context", getObjectWithPrefix(object));
336            parameters.put("profileIds", profileIds);
337            session.delete("ProfilesAssignment.deleteAllowedAnyConnected", parameters);
338        }
339    }
340    
341    
342    /* -------------------------------------- */
343    /* DENIED PROFILES FOR ANY CONNECTED USER */
344    /* -------------------------------------- */
345    
346    @Override
347    public Set<String> getDeniedProfilesForAnyConnectedUser(Object object)
348    {
349        return Optional.ofNullable(_getFullData(object).getDeniedAnyConnected().get(object))
350                .orElse(Collections.emptySet());
351    }
352    
353    @Override
354    public boolean isAnyConnectedUserDenied(Object object, String profileId)
355    {
356        return getDeniedProfilesForAnyConnectedUser(object).contains(profileId);
357    }
358    
359    @Override
360    public void addDeniedProfilesForAnyConnectedUser(Object object, Set<String> profileIds)
361    {
362        _clearCache(object);
363        
364        try (SqlSession session = getSession())
365        {
366            Object prefixedObject = getObjectWithPrefix(object);
367            
368            for (String profileId : profileIds)
369            {
370                Map<String, Object> parameters = new HashMap<>();
371                parameters.put("context", prefixedObject);
372                parameters.put("profileIds", Arrays.asList(profileId));
373                
374                List<Map<String, String>> deniedProfiles = session.selectList("ProfilesAssignment.getAnyConnectedDeniedProfiles", parameters);
375                
376                if (deniedProfiles.isEmpty())
377                {
378                    parameters.put("profileId", profileId);
379                    session.insert("ProfilesAssignment.addDeniedAnyConnected", parameters);
380                }
381                else
382                {
383                    getLogger().debug("Profile {} is already denied for anyconnected on context {}", profileId, prefixedObject);
384                }
385                
386            }
387            
388            session.commit();
389        }
390    }
391    
392    @Override
393    public void removeDeniedProfilesForAnyConnectedUser(Object object, Set<String> profileIds)
394    {
395        _clearCache(object);
396        
397        try (SqlSession session = getSession(true))
398        {
399            Map<String, Object> parameters = new HashMap<>();
400            parameters.put("context", getObjectWithPrefix(object));
401            parameters.put("profileIds", profileIds);
402            session.delete("ProfilesAssignment.deleteDeniedAnyConnected", parameters);
403        }
404    }
405    
406    
407    /* ------------------------------ */
408    /* ALLOWED PROFILES FOR ANONYMOUS */
409    /* ------------------------------ */
410    
411    @Override
412    public Set<String> getAllowedProfilesForAnonymous(Object object)
413    {
414        return Optional.ofNullable(_getFullData(object).getAllowedAnonymous().get(object))
415                .orElse(Collections.emptySet());
416    }
417    
418    @Override
419    public boolean isAnonymousAllowed(Object object, String profileId)
420    {
421        return getAllowedProfilesForAnonymous(object).contains(profileId);
422    }
423    
424    @Override
425    public void addAllowedProfilesForAnonymous(Object object, Set<String> profileIds)
426    {
427        _clearCache(object);
428        
429        try (SqlSession session = getSession())
430        {
431            Object prefixedObject = getObjectWithPrefix(object);
432            
433            for (String profileId : profileIds)
434            {
435                Map<String, Object> parameters = new HashMap<>();
436                parameters.put("context", prefixedObject);
437                parameters.put("profileIds", Arrays.asList(profileId));
438                
439                List<Map<String, String>> allowedProfiles = session.selectList("ProfilesAssignment.getAnonymousAllowedProfiles", parameters);
440                
441                if (allowedProfiles.isEmpty())
442                {
443                    parameters.put("profileId", profileId);
444                    session.insert("ProfilesAssignment.addAllowedAnonymous", parameters);
445                }
446                else
447                {
448                    getLogger().debug("Profile {} is already allowed for anonymous on context {}", profileId, prefixedObject);
449                }
450            }
451            
452            session.commit();
453        }
454    }
455    
456    @Override
457    public void removeAllowedProfilesForAnonymous(Object object, Set<String> profileIds)
458    {
459        _clearCache(object);
460        
461        try (SqlSession session = getSession(true))
462        {
463            Map<String, Object> parameters = new HashMap<>();
464            parameters.put("context", getObjectWithPrefix(object));
465            parameters.put("profileIds", profileIds);
466            session.delete("ProfilesAssignment.deleteAllowedAnonymous", parameters);
467        }
468    }
469    
470    
471    /* ----------------------------- */
472    /* DENIED PROFILES FOR ANONYMOUS */
473    /* ----------------------------- */
474    
475    @Override
476    public Set<String> getDeniedProfilesForAnonymous(Object object)
477    {
478        return Optional.ofNullable(_getFullData(object).getDeniedAnonymous().get(object))
479                .orElse(Collections.emptySet());
480    }
481    
482    @Override
483    public boolean isAnonymousDenied(Object object, String profileId)
484    {
485        return getDeniedProfilesForAnonymous(object).contains(profileId);
486    }
487    
488    @Override
489    public void addDeniedProfilesForAnonymous(Object object, Set<String> profileIds)
490    {
491        _clearCache(object);
492        
493        try (SqlSession session = getSession())
494        {
495            Object prefixedObject = getObjectWithPrefix(object);
496            for (String profileId : profileIds)
497            {
498                Map<String, Object> parameters = new HashMap<>();
499                parameters.put("context", prefixedObject);
500                parameters.put("profileIds", Arrays.asList(profileId));
501                
502                List<Map<String, String>> deniedProfiles = session.selectList("ProfilesAssignment.getAnonymousDeniedProfiles", parameters);
503                
504                if (deniedProfiles.isEmpty())
505                {
506                    parameters.put("profileId", profileId);
507                    session.insert("ProfilesAssignment.addDeniedAnonymous", parameters);
508                }
509                else
510                {
511                    getLogger().debug("Profile {} is already denied for anonymous on context {}", profileId, prefixedObject);
512                }
513            }
514            
515            session.commit();
516        }
517    }
518    
519    @Override
520    public void removeDeniedProfilesForAnonymous(Object object, Set<String> profileIds)
521    {
522        _clearCache(object);
523        
524        try (SqlSession session = getSession(true))
525        {
526            Map<String, Object> parameters = new HashMap<>();
527            parameters.put("context", getObjectWithPrefix(object));
528            parameters.put("profileIds", profileIds);
529            session.delete("ProfilesAssignment.deleteDeniedAnonymous", parameters);
530        }
531    }
532    
533    
534    /* --------------------------- */
535    /* MANAGEMENT OF ALLOWED USERS */
536    /* --------------------------- */
537    @Override
538    public Set<String> getAllowedProfilesForUser(UserIdentity user, Object object)
539    {
540        return Optional.ofNullable(_getFullData(object).getAlloweUserData().get(object))
541                .map(contextMap -> contextMap.get(user))
542                .orElse(Collections.emptySet());
543    }
544    
545    @Override
546    public Map<UserIdentity, Set<String>> getAllowedProfilesForUsers(Object object)
547    {
548        return Optional.ofNullable(_getFullData(object).getAlloweUserData().get(object))
549                .orElse(Collections.emptyMap());
550    }
551    
552    @Override
553    public Set<UserIdentity> getAllowedUsers(Object object, String profileId)
554    {
555        return Optional.ofNullable(_getFullData(object).getAlloweUserData().get(object))
556                .map(m -> m.entrySet().stream().filter(e -> e.getValue().contains(profileId)).map(e -> e.getKey()).collect(Collectors.toSet()))
557                .orElse(Collections.emptySet());
558    }
559    
560    @Override
561    public void addAllowedUsers(Set<UserIdentity> users, Object object, String profileId)
562    {
563        _clearCache(object);
564        
565        try (SqlSession session = getSession())
566        {
567            Object prefixedObject = getObjectWithPrefix(object);
568            
569            for (UserIdentity userIdentity : users)
570            {
571                Map<String, Object> parameters = new HashMap<>();
572                parameters.put("login", userIdentity.getLogin());
573                parameters.put("population", userIdentity.getPopulationId());
574                parameters.put("context", prefixedObject);
575                parameters.put("profileIds", Arrays.asList(profileId));
576                
577                List<Map<String, String>> allowedProfiles = session.selectList("ProfilesAssignment.getUserAllowedProfiles", parameters);
578                
579                if (allowedProfiles.isEmpty())
580                {
581                    parameters.put("profileId", profileId);
582                    session.insert("ProfilesAssignment.addAllowedUser", parameters);
583                }
584                else
585                {
586                    getLogger().debug("Login {} has already profile {} on context {}", userIdentity, profileId, prefixedObject);
587                }
588                
589            }
590            
591            session.commit();
592        }
593    }
594    
595    @Override
596    public void removeAllowedUsers(Set<UserIdentity> users, Object object, String profileId)
597    {
598        _clearCache(object);
599        
600        try (SqlSession session = getSession())
601        {
602            for (UserIdentity userIdentity : users)
603            {
604                Map<String, Object> parameters = new HashMap<>();
605                parameters.put("login", userIdentity.getLogin());
606                parameters.put("population", userIdentity.getPopulationId());
607                parameters.put("profileIds", Arrays.asList(profileId));
608                if (object != null)
609                {
610                    parameters.put("context", getObjectWithPrefix(object));
611                }
612                
613                session.delete("ProfilesAssignment.deleteAllowedUser", parameters);
614            }
615            session.commit();
616        }
617    }
618    
619    @Override
620    public void removeAllowedUsers(Set<UserIdentity> users, Object object)
621    {
622        _clearCache(object);
623        
624        try (SqlSession session = getSession())
625        {
626            for (UserIdentity userIdentity : users)
627            {
628                Map<String, Object> parameters = new HashMap<>();
629                parameters.put("login", userIdentity.getLogin());
630                parameters.put("population", userIdentity.getPopulationId());
631                if (object != null)
632                {
633                    parameters.put("context", getObjectWithPrefix(object));
634                }
635                
636                session.delete("ProfilesAssignment.deleteAllowedUser", parameters);
637            }
638            session.commit();
639        }
640    }
641    
642    
643    /* ---------------------------- */
644    /* MANAGEMENT OF ALLOWED GROUPS */
645    /* ---------------------------- */
646    
647    @Override
648    public Map<GroupIdentity, Set<String>> getAllowedProfilesForGroups(Object object)
649    {
650        return Optional.ofNullable(_getFullData(object).getAlloweGroupData().get(object))
651                .orElse(Collections.emptyMap());
652    }
653    
654    @Override
655    public Set<GroupIdentity> getAllowedGroups(Object object, String profileId)
656    {
657        return Optional.ofNullable(_getFullData(object).getAlloweGroupData().get(object))
658                .map(m -> m.entrySet().stream().filter(e -> e.getValue().contains(profileId)).map(e -> e.getKey()).collect(Collectors.toSet()))
659                .orElse(Collections.emptySet());
660
661    }
662    
663    @Override
664    public void addAllowedGroups(Set<GroupIdentity> groups, Object object, String profileId)
665    {
666        _clearCache(object);
667        
668        try (SqlSession session = getSession())
669        {
670            Object prefixedObject = getObjectWithPrefix(object);
671            for (GroupIdentity group : groups)
672            {
673                Map<String, Object> parameters = new HashMap<>();
674                parameters.put("groupId", group.getId());
675                parameters.put("groupDirectory", group.getDirectoryId());
676                parameters.put("context", prefixedObject);
677                parameters.put("profileIds", Arrays.asList(profileId));
678                
679                List<Map<String, String>> allowedProfiles = session.selectList("ProfilesAssignment.getGroupAllowedProfiles", parameters);
680                
681                if (allowedProfiles.isEmpty())
682                {
683                    parameters.put("profileId", profileId);
684                    session.insert("ProfilesAssignment.addAllowedGroup", parameters);
685                }
686                else
687                {
688                    getLogger().debug("Group {} is already allowed for profile {} on context {}", group, profileId, prefixedObject);
689                }
690            }
691            
692            session.commit();
693        }
694    }
695    
696    @Override
697    public void removeAllowedGroups(Set<GroupIdentity> groups, Object object, String profileId)
698    {
699        _clearCache(object);
700        
701        try (SqlSession session = getSession())
702        {
703            for (GroupIdentity group : groups)
704            {
705                Map<String, Object> parameters = new HashMap<>();
706                parameters.put("groupId", group.getId());
707                parameters.put("groupDirectory", group.getDirectoryId());
708                parameters.put("profileIds", Arrays.asList(profileId));
709                if (object != null)
710                {
711                    parameters.put("context", getObjectWithPrefix(object));
712                }
713                
714                session.delete("ProfilesAssignment.deleteAllowedGroup", parameters);
715            }
716            session.commit();
717        }
718    }
719    
720    @Override
721    public void removeAllowedGroups(Set<GroupIdentity> groups, Object object)
722    {
723        _clearCache(object);
724        
725        try (SqlSession session = getSession())
726        {
727            for (GroupIdentity group : groups)
728            {
729                Map<String, Object> parameters = new HashMap<>();
730                parameters.put("groupId", group.getId());
731                parameters.put("groupDirectory", group.getDirectoryId());
732                if (object != null)
733                {
734                    parameters.put("context", getObjectWithPrefix(object));
735                }
736                
737                session.delete("ProfilesAssignment.deleteAllowedGroup", parameters);
738            }
739            session.commit();
740        }
741    }
742    
743    
744    /* ---------------------------- */
745    /* MANAGEMENT OF DENIED USERS */
746    /* ---------------------------- */
747    @Override
748    public Set<String> getDeniedProfilesForUser(UserIdentity user, Object object)
749    {
750        return Optional.ofNullable(_getFullData(object).getDeniedUserData().get(object))
751                .map(contextMap -> contextMap.get(user))
752                .orElse(Collections.emptySet());
753    }
754    
755    @Override
756    public Map<UserIdentity, Set<String>> getDeniedProfilesForUsers(Object object)
757    {
758        return Optional.ofNullable(_getFullData(object).getDeniedUserData().get(object))
759                .orElse(Collections.emptyMap());
760    }
761    
762    @Override
763    public Set<UserIdentity> getDeniedUsers(Object object, String profileId)
764    {
765        return Optional.ofNullable(_getFullData(object).getDeniedUserData().get(object))
766                .map(m -> m.entrySet().stream().filter(e -> e.getValue().contains(profileId)).map(e -> e.getKey()).collect(Collectors.toSet()))
767                .orElse(Collections.emptySet());
768    }
769    
770    @Override
771    public void addDeniedUsers(Set<UserIdentity> users, Object object, String profileId)
772    {
773        _clearCache(object);
774        
775        try (SqlSession session = getSession())
776        {
777            Object prefixedObject = getObjectWithPrefix(object);
778            for (UserIdentity userIdentity : users)
779            {
780                Map<String, Object> parameters = new HashMap<>();
781                parameters.put("login", userIdentity.getLogin());
782                parameters.put("population", userIdentity.getPopulationId());
783                parameters.put("context", prefixedObject);
784                parameters.put("profileIds", Arrays.asList(profileId));
785                
786                List<Map<String, String>> deniedProfiles = session.selectList("ProfilesAssignment.getUserDeniedProfiles", parameters);
787                
788                if (deniedProfiles.isEmpty())
789                {
790                    parameters.put("profileId", profileId);
791                    session.insert("ProfilesAssignment.addDeniedUser", parameters);
792                }
793                else
794                {
795                    getLogger().debug("Login {} is already denied for profile {} on context {}", userIdentity, profileId, prefixedObject);
796                }
797                
798            }
799            
800            session.commit();
801        }
802    }
803    
804    @Override
805    public void removeDeniedUsers(Set<UserIdentity> users, Object object, String profileId)
806    {
807        _clearCache(object);
808        
809        try (SqlSession session = getSession())
810        {
811            for (UserIdentity userIdentity : users)
812            {
813                Map<String, Object> parameters = new HashMap<>();
814                parameters.put("login", userIdentity.getLogin());
815                parameters.put("population", userIdentity.getPopulationId());
816                parameters.put("profileIds", Arrays.asList(profileId));
817                if (object != null)
818                {
819                    parameters.put("context", getObjectWithPrefix(object));
820                }
821                
822                session.delete("ProfilesAssignment.deleteDeniedUser", parameters);
823            }
824            session.commit();
825        }
826    }
827    
828    @Override
829    public void removeDeniedUsers(Set<UserIdentity> users, Object object)
830    {
831        _clearCache(object);
832        
833        try (SqlSession session = getSession())
834        {
835            for (UserIdentity userIdentity : users)
836            {
837                Map<String, Object> parameters = new HashMap<>();
838                parameters.put("login", userIdentity.getLogin());
839                parameters.put("population", userIdentity.getPopulationId());
840                if (object != null)
841                {
842                    parameters.put("context", getObjectWithPrefix(object));
843                }
844                
845                session.delete("ProfilesAssignment.deleteDeniedUser", parameters);
846            }
847            session.commit();
848        }
849    }
850    
851    
852    /* ----------------------------- */
853    /* MANAGEMENT OF DENIED GROUPS */
854    /* ----------------------------- */
855    
856    @Override
857    public Map<GroupIdentity, Set<String>> getDeniedProfilesForGroups(Object object)
858    {
859        return Optional.ofNullable(_getFullData(object).getDeniedGroupData().get(object))
860                .orElse(Collections.emptyMap());
861    }
862    
863    @Override
864    public Set<GroupIdentity> getDeniedGroups(Object object, String profileId)
865    {
866        return Optional.ofNullable(_getFullData(object).getDeniedGroupData().get(object))
867                .map(m -> m.entrySet().stream().filter(e -> e.getValue().contains(profileId)).map(e -> e.getKey()).collect(Collectors.toSet()))
868                .orElse(Collections.emptySet());
869    }
870    
871    @Override
872    public void addDeniedGroups(Set<GroupIdentity> groups, Object object, String profileId)
873    {
874        _clearCache(object);
875        
876        try (SqlSession session = getSession())
877        {
878            Object prefixedObject = getObjectWithPrefix(object);
879            for (GroupIdentity group : groups)
880            {
881                Map<String, Object> parameters = new HashMap<>();
882                parameters.put("groupId", group.getId());
883                parameters.put("groupDirectory", group.getDirectoryId());
884                parameters.put("context", prefixedObject);
885                parameters.put("profileIds", Arrays.asList(profileId));
886                
887                List<Map<String, String>> deniedProfiles = session.selectList("ProfilesAssignment.getGroupDeniedProfiles", parameters);
888                
889                if (deniedProfiles.isEmpty())
890                {
891                    parameters.put("profileId", profileId);
892                    session.insert("ProfilesAssignment.addDeniedGroup", parameters);
893                }
894                else
895                {
896                    getLogger().debug("Group {} is already denied for profile {} on context {}", group, profileId, prefixedObject);
897                }
898            }
899            
900            session.commit();
901        }
902    }
903    
904    @Override
905    public void removeDeniedGroups(Set<GroupIdentity> groups, Object object, String profileId)
906    {
907        _clearCache(object);
908        
909        try (SqlSession session = getSession())
910        {
911            for (GroupIdentity group : groups)
912            {
913                Map<String, Object> parameters = new HashMap<>();
914                parameters.put("groupId", group.getId());
915                parameters.put("groupDirectory", group.getDirectoryId());
916                parameters.put("profileIds", Arrays.asList(profileId));
917                if (object != null)
918                {
919                    parameters.put("context", getObjectWithPrefix(object));
920                }
921                
922                session.delete("ProfilesAssignment.deleteDeniedGroup", parameters);
923            }
924            session.commit();
925        }
926    }
927    
928    @Override
929    public void removeDeniedGroups(Set<GroupIdentity> groups, Object object)
930    {
931        _clearCache(object);
932        
933        try (SqlSession session = getSession())
934        {
935            for (GroupIdentity group : groups)
936            {
937                Map<String, Object> parameters = new HashMap<>();
938                parameters.put("groupId", group.getId());
939                parameters.put("groupDirectory", group.getDirectoryId());
940                if (object != null)
941                {
942                    parameters.put("context", getObjectWithPrefix(object));
943                }
944                
945                session.delete("ProfilesAssignment.deleteDeniedGroup", parameters);
946            }
947            session.commit();
948        }
949    }
950    
951    
952    /* ------ */
953    /* REMOVE */
954    /* ------ */
955    
956    @Override
957    public void removeProfile(String profileId)
958    {
959        _clearCache();
960        
961        try (SqlSession session = getSession())
962        {
963            Map<String, Object> parameters = new HashMap<>();
964            parameters.put("profileIds", Arrays.asList(profileId));
965            
966            session.delete("ProfilesAssignment.deleteAllowedUser", parameters);
967            session.delete("ProfilesAssignment.deleteDeniedUser", parameters);
968            session.delete("ProfilesAssignment.deleteAllowedGroup", parameters);
969            session.delete("ProfilesAssignment.deleteDeniedGroup", parameters);
970            session.delete("ProfilesAssignment.deleteAllowedAnonymous", parameters);
971            session.delete("ProfilesAssignment.deleteDeniedAnonymous", parameters);
972            session.delete("ProfilesAssignment.deleteAllowedAnyConnected", parameters);
973            session.delete("ProfilesAssignment.deleteDeniedAnyConnected", parameters);
974            
975            session.commit();
976        }
977    }
978    
979    @Override
980    public void removeUser(UserIdentity user)
981    {
982        _clearCache();
983        
984        try (SqlSession session = getSession())
985        {
986            Map<String, String> parameters = new HashMap<>();
987            parameters.put("login", user.getLogin());
988            parameters.put("population", user.getPopulationId());
989            
990            session.delete("ProfilesAssignment.deleteAllowedUser", parameters);
991            session.delete("ProfilesAssignment.deleteDeniedUser", parameters);
992            
993            session.commit();
994        }
995    }
996    
997    @Override
998    public void removeGroup(GroupIdentity group)
999    {
1000        _clearCache();
1001        
1002        try (SqlSession session = getSession())
1003        {
1004            Map<String, String> parameters = new HashMap<>();
1005            parameters.put("groupId", group.getId());
1006            parameters.put("groupDirectory", group.getDirectoryId());
1007            
1008            session.delete("ProfilesAssignment.deleteAllowedGroup", parameters);
1009            session.delete("ProfilesAssignment.deleteDeniedGroup", parameters);
1010            
1011            session.commit();
1012        }
1013    }
1014    
1015    /* ------------------------------ */
1016    /* SUPPORT OF OBJECT AND PRIORITY */
1017    /* ------------------------------ */
1018
1019    public boolean isSupported(Object object)
1020    {
1021        if (object instanceof String)
1022        {
1023            String context = (String) object;
1024            return context.equals(_supportedContext) || context.startsWith(_supportedContext + "/");
1025        }
1026        return false;
1027    }
1028    
1029    public boolean isRootContextSupported(Object rootContext)
1030    {
1031        return isSupported(rootContext);
1032    }
1033
1034    @Override
1035    public int getPriority()
1036    {
1037        return ProfileAssignmentStorage.MIN_PRIORITY;
1038    }
1039    
1040    private static class Database
1041    {
1042        // Context, ProfileId
1043        private Map<String, Set<String>> _allowedAnonymousData;
1044        // Context, ProfileId
1045        private Map<String, Set<String>> _deniedAnonymousData;
1046        // Context, ProfileId
1047        private Map<String, Set<String>> _allowedAnyConnectedData;
1048        // Context, ProfileId
1049        private Map<String, Set<String>> _deniedAnyConnectedData;
1050        // Context, UserIdentity/GroupIdenty ProfileId
1051        private Map<String, Map<UserIdentity, Set<String>>> _allowedUserData;
1052        // Context, UserIdentity/GroupIdenty ProfileId
1053        private Map<String, Map<UserIdentity, Set<String>>> _deniedUserData;
1054        // Context, UserIdentity/GroupIdenty ProfileId
1055        private Map<String, Map<GroupIdentity, Set<String>>> _allowedGroupData;
1056        // Context, UserIdentity/GroupIdenty ProfileId
1057        private Map<String, Map<GroupIdentity, Set<String>>> _deniedGroupData;
1058
1059        Database(List<Map<String, String>> data)
1060        {
1061            _allowedAnonymousData = new HashMap<>();
1062            _deniedAnonymousData = new HashMap<>();
1063            _allowedAnyConnectedData = new HashMap<>();
1064            _deniedAnyConnectedData = new HashMap<>();
1065            _allowedUserData = new HashMap<>();
1066            _deniedUserData = new HashMap<>();
1067            _allowedGroupData = new HashMap<>();
1068            _deniedGroupData = new HashMap<>();
1069            
1070            for (Map<String, String> map : data)
1071            {
1072                String type = map.get("type").trim();
1073                String profileId = map.get("profileId");
1074                String context = map.get("context");
1075
1076                if ("ALLOWED_ANONYMOUS".equals(type) || "DENIED_ANONYMOUS".equals(type) || "ALLOWED_ANYCONNECTED".equals(type) || "DENIED_ANYCONNECTED".equals(type))
1077                {
1078                    _buildAnonymousOrAnyConnectedData(type, profileId, context);
1079                }
1080                else if ("ALLOWED_USER".equals(type) || "DENIED_USER".equals(type))
1081                {
1082                    String targetId = map.get("targetId");
1083                    String targetGroup = map.get("targetGroup");
1084                    UserIdentity user = new UserIdentity(targetId, targetGroup);
1085
1086                    _buildUserData(type, profileId, context, user);
1087                }
1088                else // if ("ALLOWED_GROUP".equals(type) || "DENIED_GROUP".equals(type))
1089                {
1090                    String targetId = map.get("targetId");
1091                    String targetGroup = map.get("targetGroup");
1092                    GroupIdentity group = new GroupIdentity(targetId, targetGroup);
1093                    
1094                    _buildGroupData(type, profileId, context, group);
1095                }
1096            }
1097        }
1098
1099        private void _buildGroupData(String type, String profileId, String context, GroupIdentity group)
1100        {
1101            Map<String, Map<GroupIdentity, Set<String>>> wData;
1102            if ("ALLOWED_GROUP".equals(type))
1103            {
1104                wData = _allowedGroupData;
1105            }
1106            else // if ("DENIED_GROUP".equals(type))
1107            {
1108                wData = _deniedGroupData;
1109            } 
1110
1111            if (!wData.containsKey(context))
1112            {
1113                wData.put(context, new HashMap<>());
1114            }
1115            Map<GroupIdentity, Set<String>> contextMap = wData.get(context);
1116            
1117            if (!contextMap.containsKey(group))
1118            {
1119                contextMap.put(group, new HashSet<>());
1120            }
1121            Set<String> profileSet = contextMap.get(group);
1122            
1123            profileSet.add(profileId);
1124        }
1125
1126        private void _buildUserData(String type, String profileId, String context, UserIdentity user)
1127        {
1128            Map<String, Map<UserIdentity, Set<String>>> wData;
1129            if ("ALLOWED_USER".equals(type))
1130            {
1131                wData = _allowedUserData;
1132            }
1133            else // if ("DENIED_USER".equals(type))
1134            {
1135                wData = _deniedUserData;
1136            } 
1137            
1138            if (!wData.containsKey(context))
1139            {
1140                wData.put(context, new HashMap<>());
1141            }
1142            Map<UserIdentity, Set<String>> contextMap = wData.get(context);
1143            
1144            if (!contextMap.containsKey(user))
1145            {
1146                contextMap.put(user, new HashSet<>());
1147            }
1148            Set<String> profileSet = contextMap.get(user);
1149            
1150            profileSet.add(profileId);
1151        }
1152
1153        private void _buildAnonymousOrAnyConnectedData(String type, String profileId, String context)
1154        {
1155            Map<String, Set<String>> wData;
1156            if ("ALLOWED_ANONYMOUS".equals(type))
1157            {
1158                wData = _allowedAnonymousData;
1159            }
1160            else if ("DENIED_ANONYMOUS".equals(type))
1161            {
1162                wData = _deniedAnonymousData;
1163            } 
1164            else if ("ALLOWED_ANYCONNECTED".equals(type))
1165            {
1166                wData = _allowedAnyConnectedData;
1167            } 
1168            else // if ("DENIED_ANYCONNECTED".equals(type)) 
1169            {
1170                wData = _deniedAnyConnectedData;
1171            } 
1172
1173            if (!wData.containsKey(context))
1174            {
1175                wData.put(context, new HashSet<>());
1176            }
1177            Set<String> profileSet = wData.get(context);
1178            
1179            profileSet.add(profileId);
1180        }
1181
1182        public Map<String, Set<String>> getAllowedAnonymous()
1183        {
1184            return _allowedAnonymousData;
1185        }
1186        public Map<String, Set<String>> getDeniedAnonymous()
1187        {
1188            return _deniedAnonymousData;
1189        }
1190        public Map<String, Set<String>> getAllowedAnyConnected()
1191        {
1192            return _allowedAnyConnectedData;
1193        }
1194        public Map<String, Set<String>> getDeniedAnyConnected()
1195        {
1196            return _deniedAnyConnectedData;
1197        }
1198        public Map<String, Map<UserIdentity, Set<String>>> getAlloweUserData()
1199        {
1200            return _allowedUserData;
1201        }
1202        public Map<String, Map<UserIdentity, Set<String>>> getDeniedUserData()
1203        {
1204            return _deniedUserData;
1205        }
1206        public Map<String, Map<GroupIdentity, Set<String>>> getAlloweGroupData()
1207        {
1208            return _allowedGroupData;
1209        }
1210        public Map<String, Map<GroupIdentity, Set<String>>> getDeniedGroupData()
1211        {
1212            return _deniedGroupData;
1213        }
1214    }
1215}