001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.transformation;
018:
019: import org.apache.avalon.framework.parameters.Parameters;
020: import org.apache.cocoon.ProcessingException;
021: import org.apache.cocoon.caching.CacheableProcessingComponent;
022: import org.apache.cocoon.environment.ObjectModelHelper;
023: import org.apache.cocoon.environment.Request;
024: import org.apache.cocoon.environment.SourceResolver;
025: import org.apache.excalibur.source.SourceValidity;
026: import org.xml.sax.Attributes;
027: import org.xml.sax.SAXException;
028: import org.xml.sax.helpers.AttributesImpl;
029:
030: import java.io.IOException;
031: import java.util.Map;
032: import java.util.StringTokenizer;
033:
034: /**
035: * @cocoon.sitemap.component.documentation
036: * Filter XML fragments based on a user's role. This will help in
037: * the development of smart forms that must only show information to
038: * people who are logged in and have the correct role. The Role is
039: * specified by the Request semantics. You can specify multiple roles
040: * by using comma delimiting.
041: *
042: * @cocoon.sitemap.component.name role-filter
043: * @cocoon.sitemap.component.logger sitemap.transformer.role-filter
044: *
045: * Filter XML fragments based on a user's role. This will help in
046: * the development of smart forms that must only show information to
047: * people who are logged in and have the correct role. The Role is
048: * specified by the Request semantics. You can specify multiple roles
049: * by using comma delimiting.
050: *
051: * <pre>
052: * <root xmlns:roles="http://apache.org/cocoon/role-filter/1.0">
053: * <textbox name="identifier" roles:restricted="admin,boss"/>
054: * <textbox name="name" roles:read-only="admin,boss"/>
055: * </root>
056: * </pre>
057: *
058: * The previous example will only show the "identifier" textbox for the
059: * roles "admin" and "boss". It will pass role:read-only="" if the
060: * roles "admin" or "boss" are accessing the page. That way you can
061: * specify any special processing by testing for the read-only attribute.
062: * This filter does not care about the prefix, only the namespace URI.
063: * That means you can reassign the namespace to another prefix and all
064: * will work as expected.
065: *
066: * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
067: * @version CVS $Id: RoleFilterTransformer.java 433543 2006-08-22 06:22:54Z crossley $
068: */
069: public class RoleFilterTransformer extends AbstractTransformer
070: implements CacheableProcessingComponent {
071: private final static String URI = "http://apache.org/cocoon/role-filter/1.0";
072: private final static String RESTRICT = "restricted";
073: private final static String VIEW = "read-only";
074:
075: Request request = null;
076: private int skipCounter = 0;
077:
078: public RoleFilterTransformer() {
079: }
080:
081: public final void setup(SourceResolver resolver, Map objectModel,
082: String src, Parameters params) throws ProcessingException,
083: SAXException, IOException {
084: this .request = ObjectModelHelper.getRequest(objectModel);
085: this .skipCounter = 0;
086: }
087:
088: /**
089: * Disable caching
090: */
091: public java.io.Serializable getKey() {
092: return null;
093: }
094:
095: public final void startElement(String uri, String loc, String raw,
096: Attributes a) throws SAXException {
097: if (this .skipCounter > 0) {
098: this .skipCounter++;
099: } else {
100: int roleIndex = a.getIndex(RoleFilterTransformer.URI,
101: RoleFilterTransformer.RESTRICT);
102: int viewIndex = a.getIndex(RoleFilterTransformer.URI,
103: RoleFilterTransformer.VIEW);
104: boolean propogate = true;
105: boolean readOnly = false;
106:
107: if (roleIndex >= 0) {
108: String roleRestriction = a.getValue(roleIndex);
109: StringTokenizer roles = new StringTokenizer(
110: roleRestriction, ",", false);
111: propogate = false;
112:
113: while ((!propogate) && roles.hasMoreTokens()) {
114: if (request.isUserInRole(roles.nextToken())) {
115: propogate = true;
116: }
117: }
118: }
119:
120: if (propogate) {
121: if (viewIndex >= 0) {
122: String viewRestriction = a.getValue(viewIndex);
123: StringTokenizer roles = new StringTokenizer(
124: viewRestriction, ",", false);
125:
126: while ((!readOnly) && roles.hasMoreTokens()) {
127: if (request.isUserInRole(roles.nextToken())) {
128: readOnly = true;
129: }
130: }
131: }
132: super .startElement(uri, loc, raw, this .copyAttributes(
133: a, roleIndex, viewIndex, readOnly));
134: } else {
135: this .skipCounter = 1;
136: }
137: }
138: }
139:
140: public final void endElement(String uri, String loc, String raw)
141: throws SAXException {
142: if (skipCounter > 0) {
143: skipCounter--;
144: } else {
145: super .endElement(uri, loc, raw);
146: }
147: }
148:
149: private final Attributes copyAttributes(final Attributes a,
150: final int role, final int view, boolean readOnly) {
151: if (role < 0 && view < 0) {
152: return a;
153: }
154:
155: AttributesImpl attr = new AttributesImpl();
156: attr.setAttributes(a);
157: if (role >= 0) {
158: attr.removeAttribute(role);
159: }
160:
161: if (view >= 0) {
162: if (readOnly) {
163: attr.setValue(view, "");
164: } else {
165: attr.removeAttribute(view);
166: }
167: }
168:
169: return attr;
170: }
171:
172: public void recycle() {
173: this .request = null;
174: super .recycle();
175: }
176:
177: public void startEntity(String name) throws SAXException {
178: if (this .skipCounter == 0) {
179: super .startEntity(name);
180: }
181: }
182:
183: public void endEntity(String name) throws SAXException {
184: if (this .skipCounter == 0) {
185: super .endEntity(name);
186: }
187: }
188:
189: public void comment(char[] ch, int start, int len)
190: throws SAXException {
191: if (this .skipCounter == 0) {
192: super .comment(ch, start, len);
193: }
194: }
195:
196: public void characters(char[] c, int start, int len)
197: throws SAXException {
198: if (this .skipCounter == 0) {
199: super .characters(c, start, len);
200: }
201: }
202:
203: public void startCDATA() throws SAXException {
204: if (this .skipCounter == 0) {
205: super .startCDATA();
206: }
207: }
208:
209: public void processingInstruction(String target, String data)
210: throws SAXException {
211: if (this .skipCounter == 0) {
212: super .processingInstruction(target, data);
213: }
214: }
215:
216: public SourceValidity getValidity() {
217: return null;
218: }
219:
220: public void endCDATA() throws SAXException {
221: if (this .skipCounter == 0) {
222: super.endCDATA();
223: }
224: }
225: }
|