1 package com.trendmicro.grid.acl.metadata;
2
3 import com.trendmicro.grid.acl.commons.Paths;
4 import net.sf.tinyjee.util.FileUtils;
5
6 import java.io.File;
7 import java.util.Arrays;
8 import java.util.Collection;
9 import java.util.HashSet;
10 import java.util.concurrent.Callable;
11
12 /**
13 * Is a central singleton that manages whether Metadata access is validated (and restricted) or not.
14 *
15 * @author juergen_kellerer, 2010-11-30
16 * @version 1.0
17 */
18 public final class ValidationContext implements ValidatorResolver {
19
20 public static final String DEFAULT_METADATA_PROFILES_DOCUMENT = "default-metadata-profiles.xml";
21 public static final String METADATA_PROFILES_TO_HTML = "metadata-profile-to-html.xsl";
22 public static final String METADATA_PROFILES_DOCUMENT =
23 System.getProperty("gacl.metadata.profiles", "metadata-profiles.xml");
24
25 private static final ValidationContext INSTANCE = new ValidationContext();
26
27 public static ValidationContext getInstance() {
28 return INSTANCE;
29 }
30
31 final ValidatorFactory validatorFactory;
32 final ThreadLocal<ValidationInstructions> references = new ThreadLocal<ValidationInstructions>();
33
34 private ValidationContext() {
35 try {
36 File configDir = Paths.getConfigPath();
37 File profiles = new File(configDir, METADATA_PROFILES_DOCUMENT);
38
39 ProfilesDocument profilesDocument;
40 if (profiles.isFile())
41 profilesDocument = ProfilesDocument.load(profiles);
42 else {
43 profiles = new File(configDir, DEFAULT_METADATA_PROFILES_DOCUMENT);
44 profilesDocument = ProfilesDocument.load(
45 getClass().getResourceAsStream("/" + DEFAULT_METADATA_PROFILES_DOCUMENT));
46
47 if (configDir.isDirectory()) {
48 ProfilesDocument.getXmlSerializer().save(profilesDocument, profiles, true, 4);
49 FileUtils.copy(getClass().getResourceAsStream("/" + METADATA_PROFILES_TO_HTML),
50 new File(configDir, METADATA_PROFILES_TO_HTML), true);
51 }
52 }
53
54 validatorFactory = new ProfilesDocumentValidatorFactory(profilesDocument);
55 } catch (Exception e) {
56 throw new RuntimeException(e);
57 }
58 }
59
60 /**
61 * Returns the thread local reference values that are used by the validator to restrict access.
62 *
63 * @return the thread local reference values that are used by the validator to restrict access.
64 * @see #enableValidation(String, AccessLevel, String...)
65 * @see #enableValidation(String, AccessLevel, java.util.Collection)
66 * @see #disableValidation()
67 */
68 public ValidationInstructions getActiveValidationInstructions() {
69 return references.get();
70 }
71
72 /**
73 * Enables Metadata access validation and restriction on the current Thread, using the given protection
74 * level and user roles as reference.
75 *
76 * @param fqProfileName The full qualified name of the validation profile to apply.
77 * See {@link WellKnownProfileNames} for a collection of known profiles.
78 * @param level the level to execute validation on.
79 * @param roles the list of roles that the current user belongs to (if any).
80 * @see #enableValidation(String, AccessLevel, String...)
81 * @see #disableValidation()
82 */
83 public void enableValidation(String fqProfileName, AccessLevel level, Collection<String> roles) {
84 if (fqProfileName == null)
85 disableValidation();
86 else {
87 final ValidationInstructions currentInstructions = references.get();
88 if (currentInstructions != null) {
89 if (currentInstructions.getActiveProfileName().equals(fqProfileName) &&
90 currentInstructions.getLevel() == level &&
91 currentInstructions.getRoles().equals(roles))
92 return;
93 }
94
95 references.set(new ValidationInstructions(fqProfileName, level, roles));
96 }
97 }
98
99 /**
100 * Enables Metadata access validation and restriction on the current Thread, using the given protection
101 * level and user roles as reference.
102 *
103 * @param fqProfileName The full qualified name of the validation profile to apply.
104 * See {@link WellKnownProfileNames} for a collection of known profiles.
105 * @param level the level to execute validation on.
106 * @param roles the list of roles that the current user belongs to (if any).
107 * @see #enableValidation(String, AccessLevel, java.util.Collection)
108 * @see #disableValidation()
109 */
110 public void enableValidation(String fqProfileName, AccessLevel level, String... roles) {
111 enableValidation(fqProfileName, level, new HashSet<String>(Arrays.asList(roles)));
112 }
113
114 /**
115 * Disables Metadata validation on the current Thread.
116 *
117 * @see #enableValidation(String, AccessLevel, String...)
118 * @see #enableValidation(String, AccessLevel, java.util.Collection)
119 */
120 public void disableValidation() {
121 references.remove();
122 }
123
124 /**
125 * {@inheritDoc}
126 */
127 @Override
128 public Validator getValidator() {
129 final ValidationInstructions ref = references.get();
130 return ref == null ? null : validatorFactory.newValidator(ref);
131 }
132
133 /**
134 * Performs the given operation with disabled validation on metadata access rights.
135 * <p/>
136 * Any operations on metadata that must not result in user and profile related filtering has to be
137 * wrapped in a callable and used with this method in order to ensure metadata is fully processed
138 * including any values that are not visible to the user session, access level and profile that is bound
139 * to the executing thread.
140 * <p/>
141 * Example:<code><pre>
142 * // Read a shareable metadata instance containing everything
143 * return ValidationContext.getInstance().doUnvalidated(new Callable<Metadata>() {
144 * public Metadata call() throws Exception {
145 * return (Metadata) unmarshaller.unmarshall(streamFromDatabase);
146 * }
147 * });
148 * // Read a user session bound metadata instance containing what is visible to the current user.
149 * return (Metadata) unmarshaller.unmarshall(streamFromDatabase);
150 * </pre></code>
151 * <p/>
152 * <b>Note:</b> The sort of filtering that is applied depends on what was previously configured in
153 * {@link #enableValidation(String, AccessLevel, String...)}. Using this method allows to bypass any restrictions
154 * that would normally apply to instances of {@link Metadata}.
155 *
156 * @param callable the callable that performs the operation.
157 * @param <V> the return type.
158 * @return the value returned by the callable.
159 * @throws Exception the exception thrown by the callable.
160 */
161 public <V> V doUnvalidated(Callable<V> callable) throws Exception {
162 final ValidationInstructions instructions = references.get();
163 try {
164 references.remove();
165 return callable.call();
166 } finally {
167 references.set(instructions);
168 }
169 }
170 }