I've made an Oracle 9 adapter, I've tested it with Konqueror on Linux,
Explorer on Windows and it seems to work... There's no support for
compression yet. In storeContent() I use a method of the Oracle JDBC driver,
someone knows if it could be implemented without it?
Is there a test suite for Stores???
--
Davide Savazzi
ALTER SESSION SET SQL_TRACE = TRUE;
DROP TRIGGER "URI-URI_ID-TRG";
DROP TRIGGER "BRANCH-BRANCH_ID-TRG";
DROP TRIGGER "LABEL-LABEL_ID-TRG";
DROP TRIGGER "VERSION_HISTORY-VERSION_ID-TRG";
DROP SEQUENCE "URI-URI_ID-SEQ";
DROP SEQUENCE "BRANCH-BRANCH_ID-SEQ";
DROP SEQUENCE "LABEL-LABEL_ID-SEQ";
DROP SEQUENCE "VERSION_HISTORY-VERSION_ID-SEQ";
DROP TABLE "URI" CASCADE CONSTRAINTS;
DROP TABLE "OBJECT" CASCADE CONSTRAINTS;
DROP TABLE "BINDING" CASCADE CONSTRAINTS;
DROP TABLE "PARENT_BINDING" CASCADE CONSTRAINTS;
DROP TABLE "LINKS" CASCADE CONSTRAINTS;
DROP TABLE "LOCKS" CASCADE CONSTRAINTS;
DROP TABLE "BRANCH" CASCADE CONSTRAINTS;
DROP TABLE "LABEL" CASCADE CONSTRAINTS;
DROP TABLE "VERSION" CASCADE CONSTRAINTS;
DROP TABLE "VERSION_HISTORY" CASCADE CONSTRAINTS;
DROP TABLE "VERSION_PREDS" CASCADE CONSTRAINTS;
DROP TABLE "VERSION_LABELS" CASCADE CONSTRAINTS;
DROP TABLE "VERSION_CONTENT" CASCADE CONSTRAINTS;
DROP TABLE "PROPERTIES" CASCADE CONSTRAINTS;
DROP TABLE "PERMISSIONS" CASCADE CONSTRAINTS;
// path max length: 2500
CREATE TABLE "URI" (
"URI_ID" NUMBER(10) NOT NULL,
"URI_STRING" VARCHAR2(2500) NOT NULL,
PRIMARY KEY("URI_ID"),
UNIQUE("URI_STRING")
) CACHE NOLOGGING;
CREATE TABLE "OBJECT" (
"URI_ID" NUMBER(10),
"CLASS_NAME" VARCHAR2(255) NOT NULL,
PRIMARY KEY("URI_ID"),
FOREIGN KEY("URI_ID") REFERENCES "URI"("URI_ID")
) CACHE NOLOGGING;
// node name max length: 512
CREATE TABLE "BINDING" (
"URI_ID" NUMBER(10) NOT NULL,
"NAME" VARCHAR2(512) NOT NULL,
"CHILD_UURI_ID" NUMBER(10) NOT NULL,
PRIMARY KEY("URI_ID", "NAME", "CHILD_UURI_ID"),
FOREIGN KEY("URI_ID") REFERENCES "URI"("URI_ID"),
FOREIGN KEY("CHILD_UURI_ID") REFERENCES "URI"("URI_ID")
) CACHE NOLOGGING;
CREATE TABLE "PARENT_BINDING" (
"URI_ID" NUMBER(10) NOT NULL,
"NAME" VARCHAR2(512) NOT NULL,
"PARENT_UURI_ID" NUMBER(10) NOT NULL,
PRIMARY KEY("URI_ID", "NAME", "PARENT_UURI_ID"),
FOREIGN KEY("URI_ID") REFERENCES "URI"("URI_ID"),
FOREIGN KEY("PARENT_UURI_ID") REFERENCES "URI"("URI_ID")
) CACHE NOLOGGING;
CREATE TABLE "LINKS" (
"URI_ID" NUMBER(10) NOT NULL,
"LINK_TO_ID" NUMBER(10) NOT NULL,
PRIMARY KEY("URI_ID", "LINK_TO_ID"),
FOREIGN KEY("URI_ID") REFERENCES "URI"("URI_ID"),
FOREIGN KEY("LINK_TO_ID") REFERENCES "URI"("URI_ID")
) CACHE NOLOGGING;
CREATE TABLE "LOCKS" (
"LOCK_ID" NUMBER(10) NOT NULL,
"OBJECT_ID" NUMBER(10) NOT NULL,
"SUBJECT_ID" NUMBER(10) NOT NULL,
"TYPE_ID" NUMBER(10) NOT NULL,
"EXPIRATION_DATE" NUMBER(14) NOT NULL,
"IS_INHERITABLE" NUMBER(1) NOT NULL,
"IS_EXCLUSIVE" NUMBER(1) NOT NULL,
"OWNER" VARCHAR2(512),
PRIMARY KEY("LOCK_ID"),
FOREIGN KEY("LOCK_ID") REFERENCES "URI"("URI_ID"),
FOREIGN KEY("OBJECT_ID") REFERENCES "URI"("URI_ID"),
FOREIGN KEY("SUBJECT_ID") REFERENCES "URI"("URI_ID"),
FOREIGN KEY("TYPE_ID") REFERENCES "URI"("URI_ID")
) CACHE NOLOGGING;
CREATE TABLE "BRANCH" (
"BRANCH_ID" NUMBER(10) NOT NULL,
"BRANCH_STRING" VARCHAR2(512) NOT NULL,
PRIMARY KEY("BRANCH_ID"),
UNIQUE("BRANCH_STRING")
) CACHE NOLOGGING;
CREATE TABLE "LABEL" (
"LABEL_ID" NUMBER(10) NOT NULL,
"LABEL_STRING" VARCHAR2(512) NOT NULL,
PRIMARY KEY("LABEL_ID")
) CACHE NOLOGGING;
CREATE TABLE "VERSION" (
"URI_ID" NUMBER(10) NOT NULL,
"IS_VERSIONED" NUMBER(1) NOT NULL,
PRIMARY KEY("URI_ID"),
FOREIGN KEY("URI_ID") REFERENCES "URI"("URI_ID")
) CACHE NOLOGGING;
CREATE TABLE "VERSION_HISTORY" (
"VERSION_ID" NUMBER(10) NOT NULL,
"URI_ID" NUMBER(10) NOT NULL,
"BRANCH_ID" NUMBER(10) NOT NULL,
"REVISION_NO" VARCHAR2(20) NOT NULL,
PRIMARY KEY("VERSION_ID"),
UNIQUE("URI_ID", "BRANCH_ID", "REVISION_NO"),
FOREIGN KEY("URI_ID") REFERENCES "URI"("URI_ID"),
FOREIGN KEY("BRANCH_ID") REFERENCES "BRANCH"("BRANCH_ID")
) CACHE NOLOGGING;
CREATE TABLE "VERSION_PREDS" (
"VERSION_ID" NUMBER(10) NOT NULL,
"PREDECESSOR_ID" NUMBER(10) NOT NULL,
FOREIGN KEY("VERSION_ID") REFERENCES "VERSION_HISTORY"("VERSION_ID"),
FOREIGN KEY("PREDECESSOR_ID") REFERENCES "VERSION_HISTORY"("VERSION_ID"),
UNIQUE("VERSION_ID", "PREDECESSOR_ID")
) CACHE NOLOGGING;
CREATE TABLE "VERSION_LABELS" (
"VERSION_ID" NUMBER(10) NOT NULL,
"LABEL_ID" NUMBER(10) NOT NULL,
UNIQUE("VERSION_ID", "LABEL_ID"),
FOREIGN KEY("VERSION_ID") REFERENCES "VERSION_HISTORY"("VERSION_ID"),
FOREIGN KEY("LABEL_ID") REFERENCES "LABEL"("LABEL_ID")
) CACHE NOLOGGING;
CREATE TABLE "VERSION_CONTENT" (
"VERSION_ID" NUMBER(10) NOT NULL,
"CONTENT" BLOB,
PRIMARY KEY("VERSION_ID"),
FOREIGN KEY("VERSION_ID") REFERENCES "VERSION_HISTORY"("VERSION_ID")
) CACHE NOLOGGING
LOB ("CONTENT") STORE AS (NOCACHE NOLOGGING STORAGE(MAXEXTENTS UNLIMITED));
CREATE TABLE "PROPERTIES" (
"VERSION_ID" NUMBER(10) NOT NULL,
"PROPERTY_NAMESPACE" VARCHAR2(50) NOT NULL,
"PROPERTY_NAME" VARCHAR2(50) NOT NULL,
"PROPERTY_VALUE" VARCHAR2(255),
"PROPERTY_TYPE" VARCHAR2(50),
"IS_PROTECTED" NUMBER(1) NOT NULL,
UNIQUE("VERSION_ID", "PROPERTY_NAMESPACE", "PROPERTY_NAME"),
FOREIGN KEY("VERSION_ID") REFERENCES "VERSION_HISTORY"("VERSION_ID")
) CACHE NOLOGGING;
CREATE TABLE "PERMISSIONS" (
"OBJECT_ID" NUMBER(10) NOT NULL,
"SUBJECT_ID" NUMBER(10) NOT NULL,
"ACTION_ID" NUMBER(10) NOT NULL,
"VERSION_NO" VARCHAR2(20),
"IS_INHERITABLE" NUMBER(1) NOT NULL,
"IS_NEGATIVE" NUMBER(1) NOT NULL,
"SUCCESSION" NUMBER(10) NOT NULL,
FOREIGN KEY("OBJECT_ID") REFERENCES "URI"("URI_ID"),
FOREIGN KEY("SUBJECT_ID") REFERENCES "URI"("URI_ID"),
FOREIGN KEY("ACTION_ID") REFERENCES "URI"("URI_ID"),
UNIQUE("OBJECT_ID", "SUBJECT_ID", "ACTION_ID"),
UNIQUE("OBJECT_ID", "SUCCESSION")
) CACHE NOLOGGING;
CREATE SEQUENCE "URI-URI_ID-SEQ" START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
CREATE SEQUENCE "BRANCH-BRANCH_ID-SEQ" START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
CREATE SEQUENCE "LABEL-LABEL_ID-SEQ" START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
CREATE SEQUENCE "VERSION_HISTORY-VERSION_ID-SEQ" START WITH 1 INCREMENT BY 1 NOCACHE
NOCYCLE;
CREATE TRIGGER "URI-URI_ID-TRG" BEFORE INSERT ON "URI" FOR EACH ROW
BEGIN
SELECT "URI-URI_ID-SEQ".nextval INTO :new.URI_ID from dual;
END;
/
CREATE TRIGGER "BRANCH-BRANCH_ID-TRG" BEFORE INSERT ON "BRANCH" FOR EACH ROW
BEGIN
SELECT "BRANCH-BRANCH_ID-SEQ".nextval INTO :new.BRANCH_ID from dual;
END;
/
CREATE TRIGGER "LABEL-LABEL_ID-TRG" BEFORE INSERT ON "LABEL" FOR EACH ROW
BEGIN
SELECT "LABEL-LABEL_ID-SEQ".nextval INTO :new.LABEL_ID from dual;
END;
/
CREATE TRIGGER "VERSION_HISTORY-VERSION_ID-TRG" BEFORE INSERT ON "VERSION_HISTORY" FOR
EACH ROW
BEGIN
SELECT "VERSION_HISTORY-VERSION_ID-SEQ".nextval INTO :new.VERSION_ID from dual;
END;
/
package org.apache.slide.store.impl.rdbms;
import org.apache.slide.common.*;
import org.apache.slide.content.*;
import org.apache.slide.lock.LockTokenNotFoundException;
import org.apache.slide.lock.NodeLock;
import org.apache.slide.security.NodePermission;
import org.apache.slide.structure.LinkNode;
import org.apache.slide.structure.ObjectAlreadyExistsException;
import org.apache.slide.structure.ObjectNode;
import org.apache.slide.structure.ObjectNotFoundException;
import org.apache.slide.util.logger.Logger;
import java.io.*;
//import java.util.zip.GZIPOutputStream;
//import java.util.zip.GZIPInputStream;
import java.sql.*;
import java.util.*;
/**
* @todo compression support
*
* @author Davide Savazzi
*/
public class OracleRDBMSAdapter extends StandardRDBMSAdapter {
// Constructor
public OracleRDBMSAdapter(Service service, Logger logger) {
super(service, logger);
}
// Public Methods
public void removeObject(Connection connection, Uri uri, ObjectNode object)
throws ServiceAccessException, ObjectNotFoundException
{
PreparedStatement statement = null;
try {
clearBinding(connection, uri);
// delete links
try {
statement =
connection.prepareStatement(
"delete from LINKS l where l.URI_ID in (" +
"select u.URI_ID from URI u where u.URI_STRING = ?)");
statement.setString(1, uri.toString());
statement.executeUpdate();
} finally {
close(statement);
}
// delete version history
// FIXME: Is this true??? Should the version history be removed if the object is removed???
try {
statement =
connection.prepareStatement(
"delete from VERSION_HISTORY vh where vh.URI_ID in (" +
"select u.URI_ID from URI u where u.URI_STRING = ?)");
statement.setString(1, uri.toString());
statement.executeUpdate();
} finally {
close(statement);
}
// delete version
try {
statement =
connection.prepareStatement(
"delete from VERSION v where v.URI_ID in (" +
"select u.URI_ID from URI u where u.URI_STRING = ?)");
statement.setString(1, uri.toString());
statement.executeUpdate();
} finally {
close(statement);
}
// delete the object itself
try {
statement =
connection.prepareStatement(
"delete from OBJECT o where o.URI_ID in (" +
"select u.URI_ID from URI u where u.URI_STRING = ?)");
statement.setString(1, uri.toString());
statement.executeUpdate();
} finally {
close(statement);
}
// finally delete the uri
try {
statement = connection.prepareStatement("delete from URI where URI_STRING = ?");
statement.setString(1, uri.toString());
statement.executeUpdate();
} finally {
close(statement);
}
} catch (SQLException e) {
throw createException(e, uri.toString());
}
}
public void removeRevisionContent(Connection connection, Uri uri, NodeRevisionDescriptor revisionDescriptor)
throws ServiceAccessException {
try {
PreparedStatement statement = null;
try {
statement =
connection.prepareStatement(
"delete from VERSION_CONTENT vc where vc.VERSION_ID in (" +
"select vh.VERSION_ID from VERSION_HISTORY vh, URI u where vh.REVISION_NO = ? and vh.URI_ID=u.URI_ID AND u.URI_STRING=?)");
// "delete VERSION_CONTENT from VERSION_CONTENT vc, VERSION_HISTORY vh, URI u where vc.VERSION_ID = vh.VERSION_ID and vh.REVISION_NO = ? and vh.URI_ID=u.URI_ID AND u.URI_STRING=?");
statement.setString(1, revisionDescriptor.getRevisionNumber().toString());
statement.setString(2, uri.toString());
statement.executeUpdate();
} finally {
close(statement);
}
} catch (SQLException e) {
throw createException(e, uri.toString());
}
}
public void removeRevisionDescriptors(Connection connection, Uri uri) throws ServiceAccessException {
PreparedStatement statement = null;
try {
statement =
connection.prepareStatement(
"delete from VERSION_PREDS vp where vp.VERSION_ID in (" +
"select vh.VERSION_ID from VERSION_HISTORY vh, URI u where vh.URI_ID = u.URI_ID and u.URI_STRING = ?)");
// "delete VERSION_PREDS from VERSION_PREDS vp, VERSION_HISTORY vh, URI u where vp.VERSION_ID = vh.VERSION_ID and vh.URI_ID = u.URI_ID and u.URI_STRING = ?");
statement.setString(1, uri.toString());
statement.executeUpdate();
} catch (SQLException e) {
throw createException(e, uri.toString());
} finally {
close(statement);
}
}
public void removeRevisionDescriptor(Connection connection, Uri uri, NodeRevisionNumber revisionNumber)
throws ServiceAccessException
{
PreparedStatement statement = null;
try {
try {
statement =
connection.prepareStatement(
"delete from VERSION_LABELS vl where vl.VERSION_ID in (" +
"select vh.VERSION_ID from VERSION_HISTORY vh, URI u where vh.REVISION_NO = ? and vh.URI_ID = u.URI_ID AND u.URI_STRING = ?)");
// "delete VERSION_LABELS from VERSION_LABELS vl, VERSION_HISTORY vh, URI u where vl.VERSION_ID = vh.VERSION_ID and vh.REVISION_NO = ? and vh.URI_ID = u.URI_ID AND u.URI_STRING = ?");
statement.setString(1, revisionNumber.toString());
statement.setString(2, uri.toString());
statement.executeUpdate();
} finally {
close(statement);
}
try {
statement =
connection.prepareStatement(
"delete from PROPERTIES p where p.VERSION_ID in (" +
"select vh.VERSION_ID from VERSION_HISTORY vh, URI u where vh.REVISION_NO = ? and vh.URI_ID = u.URI_ID AND u.URI_STRING = ?)");
// "delete PROPERTIES from PROPERTIES p, VERSION_HISTORY vh, URI u where p.VERSION_ID = vh.VERSION_ID and vh.REVISION_NO = ? and vh.URI_ID = u.URI_ID AND u.URI_STRING = ?");
statement.setString(1, revisionNumber.toString());
statement.setString(2, uri.toString());
statement.executeUpdate();
} finally {
close(statement);
}
} catch (SQLException e) {
throw createException(e, uri.toString());
}
}
public void removeLock(Connection connection, Uri uri, NodeLock lock)
throws ServiceAccessException, LockTokenNotFoundException {
PreparedStatement statement = null;
try {
// FIXME: What about inheritage?
try {
statement =
connection.prepareStatement(
"delete from LOCKS where LOCKS.LOCK_ID in (select u.URI_ID from URI u where u.URI_STRING=?)");
// "delete LOCKS from LOCKS, URI u where LOCK_ID = u.URI_ID and u.URI_STRING=?");
statement.setString(1, lock.getLockId());
statement.executeUpdate();
} finally {
close(statement);
}
try {
statement =
connection.prepareStatement(
"delete from URI where URI.URI_ID in (select LOCK_ID from LOCKS) and URI_STRING=?");
// "delete URI from URI, LOCKS l where URI_ID = l.LOCK_ID and URI_STRING=?");
statement.setString(1, lock.getLockId());
statement.executeUpdate();
} finally {
close(statement);
}
} catch (SQLException e) {
throw createException(e, uri.toString());
}
}
public void revokePermission(Connection connection, Uri uri, NodePermission permission)
throws ServiceAccessException {
PreparedStatement statement = null;
try {
NodeRevisionNumber revisionNumber = permission.getRevisionNumber();
statement =
connection.prepareStatement(
"delete from PERMISSIONS where PERMISSIONS.OBJECT_ID in (select ou.URI_ID from URI ou, URI su, URI au where ou.URI_STRING = ? and SUBJECT_ID = su.URI_ID and su.URI_STRING = ? and ACTION_ID = au.URI_ID and au.URI_STRING = ? and VERSION_NO"
+ getRevisionNumberAsWhereQueryFragement(revisionNumber) + ")");
// "delete PERMISSIONS from PERMISSIONS, URI ou, URI su, URI au where OBJECT_ID = ou.URI_ID and ou.URI_STRING = ? and SUBJECT_ID = su.URI_ID and su.URI_STRING = ? and ACTION_ID = au.URI_ID and au.URI_STRING = ? and VERSION_NO"
// + getRevisionNumberAsWhereQueryFragement(revisionNumber));
statement.setString(1, permission.getObjectUri());
statement.setString(2, permission.getSubjectUri());
statement.setString(3, permission.getActionUri());
statement.executeUpdate();
} catch (SQLException e) {
throw createException(e, uri.toString());
} finally {
close(statement);
}
}
public void revokePermissions(Connection connection, Uri uri) throws ServiceAccessException {
PreparedStatement statement = null;
try {
statement =
connection.prepareStatement(
"delete from PERMISSIONS where PERMISSIONS.OBJECT_ID in (select u.URI_ID from URI u where u.URI_STRING = ?)");
// "delete PERMISSIONS from PERMISSIONS, URI u where OBJECT_ID = u.URI_ID and u.URI_STRING = ?");
statement.setString(1, uri.toString());
statement.executeUpdate();
} catch (SQLException e) {
throw createException(e, uri.toString());
} finally {
close(statement);
}
}
// Private Methods
protected void storeContent(
Connection connection,
Uri uri,
NodeRevisionDescriptor revisionDescriptor,
NodeRevisionContent revisionContent)
throws IOException, SQLException
{
getLogger().log("storeContent: " + uri, Logger.DEBUG);
assureVersionInfo(connection, uri, revisionDescriptor);
long versionContentId = getVersionContentId(connection, uri, revisionDescriptor);
insertEmptyContent(connection, versionContentId);
PreparedStatement statement = connection.prepareStatement(
"SELECT vc.CONTENT FROM VERSION_CONTENT vc WHERE vc.VERSION_ID = ? FOR UPDATE");
try {
statement.setLong(1, versionContentId);
ResultSet res = statement.executeQuery();
try {
res.next();
Blob blob = res.getBlob(1);
InputStream in = revisionContent.streamContent();
// OutputStream out = new GZIPOutputStream(
// ((oracle.sql.BLOB) blob).getBinaryOutputStream());
OutputStream out = ((oracle.sql.BLOB) blob).getBinaryOutputStream();
try {
copy(in, out, ((oracle.sql.BLOB) blob).getBufferSize());
} finally {
close(out);
}
} finally {
close(res);
}
} finally {
close(statement);
}
}
protected void clearBinding(Connection connection, Uri uri)
throws ServiceAccessException, ObjectNotFoundException, SQLException
{
PreparedStatement statement = null;
try {
statement =
connection.prepareStatement(
"delete from BINDING where BINDING.URI_ID in (select URI_ID from URI where URI.URI_STRING = ?)");
// "delete BINDING from BINDING c, URI u where c.URI_ID = u.URI_ID and u.URI_STRING = ?");
statement.setString(1, uri.toString());
statement.executeUpdate();
} finally {
close(statement);
}
try {
statement =
connection.prepareStatement(
"delete from PARENT_BINDING where PARENT_BINDING.URI_ID in (select URI_ID from URI where URI.URI_STRING = ?)");
// "delete PARENT_BINDING from PARENT_BINDING c, URI u where c.URI_ID = u.URI_ID and u.URI_STRING = ?");
statement.setString(1, uri.toString());
statement.executeUpdate();
} finally {
close(statement);
}
}
protected ServiceAccessException createException(SQLException sqle, String uri) {
if (getLogger().isEnabled(Logger.DEBUG)) {
sqle.printStackTrace();
}
return new ServiceAccessException(service, sqle);
}
private long getVersionContentId(Connection connection, Uri uri, NodeRevisionDescriptor revisionDescriptor)
throws SQLException
{
PreparedStatement statement = connection.prepareStatement(
"select vh.VERSION_ID from VERSION_HISTORY vh, URI u " +
"where vh.URI_ID = u.URI_ID and u.URI_STRING = ? and vh.REVISION_NO"
+ getRevisionNumberAsWhereQueryFragement(revisionDescriptor.getRevisionNumber()));
try {
statement.setString(1, uri.toString());
ResultSet res = statement.executeQuery();
try {
res.next();
return res.getLong(1);
} finally {
close(res);
}
} finally {
close(statement);
}
}
private void insertEmptyContent(Connection connection, long versionContentId)
throws SQLException
{
PreparedStatement statement = connection.prepareStatement(
"insert into VERSION_CONTENT (VERSION_ID, CONTENT) values (?, EMPTY_BLOB())");
try {
statement.setLong(1, versionContentId);
statement.executeUpdate();
} finally {
close(statement);
}
}
private void close(ResultSet resultSet) {
try {
if (resultSet != null) {
resultSet.close();
}
} catch (SQLException e) {
getLogger().log(e, LOG_CHANNEL, Logger.WARNING);
}
}
private void close(InputStream in) {
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
getLogger().log(e, LOG_CHANNEL, Logger.WARNING);
}
}
private void close(OutputStream out) {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
getLogger().log(e, LOG_CHANNEL, Logger.WARNING);
}
}
private static void copy(InputStream in, OutputStream out, int bufferSize)
throws IOException
{
int read = 0;
byte buffer[] = new byte[bufferSize];
while ((read = in.read(buffer, 0, bufferSize)) != -1) {
out.write(buffer, 0, read);
}
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]