The JDBC subject source has queries to search by ID, identifier, and freeform. The JDBC2 subject source, has a table or view with those columns, and constructs the queries for you. If possible you should use the JDBC2 subject source. The JDBC source has issues with pooling if you have a less than reliable network.
Ideally you would create a table or materialized view and migrate data there, and build the JDBC2 subject source. This will have the best performance.
Here are some sample columns you need:
- subject_id (opaque id)
- netId (blank for external users)
- eppn
- name
- description (how you want the subject to display)
- lower_search_field (lower case list of things to search e.g. comma separated. this might just be the lower case description)
- first (if you want for subject attribute)
- last (if you want for subject attribute)
- any other things you want to expose as subject attributes, usually this is a short list since Grouper is not your IdM
If you cannot load data into a table or materialized view, then you should make a view of the data and build the JDBC2 subject source from that view. Note, if you have a flattened table already (no concatenations, joins, etc), then a view is fine to use (table would not be faster)
If you cannot do either of those, you can make a query that will be used as a table
For instance, here is a table of users (example from florida)
CREATE TABLE ARP_PERSON_INFO ( ARP_PAR_UFID VARCHAR2(8 CHAR) NOT NULL, ARP_PAR_GLID VARCHAR2(16 CHAR) NOT NULL, ARP_PAR_BUSINESS_NM VARCHAR2(44 CHAR) NOT NULL, ARP_PAR_DISPLAY_NM VARCHAR2(44 CHAR) NOT NULL, ARP_PAR_DIR_NM VARCHAR2(44 CHAR) NOT NULL, ARP_PAR_FIRST_NM VARCHAR2(44 CHAR) NOT NULL, ARP_PAR_MIDDLE_NM VARCHAR2(44 CHAR) NOT NULL, ARP_PAR_LAST_NM VARCHAR2(44 CHAR) NOT NULL, ARP_PAR_SUFFIX_NM VARCHAR2(44 CHAR) NOT NULL, ARP_PAR_PHONE_STRING VARCHAR2(30 CHAR) NOT NULL, ARP_PAR_POSTAL_ADDR VARCHAR2(254 CHAR) NOT NULL, ARP_PAR_UF_EMAIL_AD VARCHAR2(254 CHAR) NOT NULL, ARP_PAR_STATUS_FLG VARCHAR2(1 CHAR) NOT NULL, ARP_PAR_PROTECT_FLG VARCHAR2(1 CHAR) NOT NULL, ARP_PAR_PRI_AFF_TYPE VARCHAR2(1 CHAR) NOT NULL, ARP_PAR_PRIMARY_DEPTID VARCHAR2(8 CHAR) NOT NULL, ARP_PAR_CLASS_COLLEGE VARCHAR2(3 CHAR) NOT NULL, ARP_PAR_MAJOR_LIST VARCHAR2(254 CHAR) NOT NULL, ARP_PAR_MINOR_LIST VARCHAR2(254 CHAR) NOT NULL, ARP_PAR_LOA VARCHAR2(20 CHAR) NOT NULL, ARP_PAR_CERTIFICATES_LIST VARCHAR2(254 CHAR) NOT NULL, ARP_PAR_NET_MANAGEDBY VARCHAR2(8 CHAR) DEFAULT ' ' NOT NULL ); Insert into ARP_PERSON_INFO (ARP_PAR_UFID, ARP_PAR_GLID, ARP_PAR_BUSINESS_NM, ARP_PAR_DISPLAY_NM, ARP_PAR_DIR_NM, ARP_PAR_FIRST_NM, ARP_PAR_MIDDLE_NM, ARP_PAR_LAST_NM, ARP_PAR_SUFFIX_NM, ARP_PAR_PHONE_STRING, ARP_PAR_POSTAL_ADDR, ARP_PAR_UF_EMAIL_AD, ARP_PAR_STATUS_FLG, ARP_PAR_PROTECT_FLG, ARP_PAR_PRI_AFF_TYPE, ARP_PAR_PRIMARY_DEPTID, ARP_PAR_CLASS_COLLEGE, ARP_PAR_MAJOR_LIST, ARP_PAR_MINOR_LIST, ARP_PAR_LOA, ARP_PAR_CERTIFICATES_LIST, ARP_PAR_NET_MANAGEDBY) Values ('123', 'mchyzer', ' ', ' ', ' ', 'Chris', 'Michael', 'Hyzer', ' ', ' ', ' ', 'mchyzer@isc.upenn.edu', 'A', 'F', 'S', 'ISC', ' ', ' ', ' ', ' ', ' ', ' '); COMMIT;
For instance, if this is the query:
SELECT id, netId, name, email, description, LOWER (description) AS search_description FROM (SELECT s.ARP_PAR_GLID || '@ufl.edu' AS id, s.ARP_PAR_GLID AS netId, s.ARP_PAR_UF_EMAIL_AD AS email, TRIM (s.ARP_PAR_FIRST_NM) || ' ' || CASE WHEN LENGTH (TRIM (s.ARP_PAR_MIDDLE_NM)) > 0 THEN TRIM (s.ARP_PAR_MIDDLE_NM) || ' ' END || CASE WHEN LENGTH (TRIM (s.ARP_PAR_LAST_NM)) > 0 THEN TRIM (s.ARP_PAR_LAST_NM) END || CASE WHEN LENGTH (TRIM (s.ARP_PAR_SUFFIX_NM)) > 0 THEN ' ' || TRIM (s.ARP_PAR_SUFFIX_NM) END AS name, TRIM (s.ARP_PAR_FIRST_NM) || ' ' || CASE WHEN LENGTH (TRIM (s.ARP_PAR_MIDDLE_NM)) > 0 THEN TRIM (s.ARP_PAR_MIDDLE_NM) || ' ' END || CASE WHEN LENGTH (TRIM (s.ARP_PAR_LAST_NM)) > 0 THEN TRIM (s.ARP_PAR_LAST_NM) END || CASE WHEN LENGTH (TRIM (s.ARP_PAR_SUFFIX_NM)) > 0 THEN ' ' || TRIM (s.ARP_PAR_SUFFIX_NM) END || ', ' || s.ARP_PAR_GLID || '@ufl.edu, ' || s.ARP_PAR_PRI_AFF_TYPE || ', ' || s.ARP_PAR_PRIMARY_DEPTID || ', ' || s.ARP_PAR_UF_EMAIL_AD AS description FROM ARP_PERSON_INFO s WHERE s.ARP_PAR_STATUS_FLG = 'A')
You can use that query to setup a subject source in jdbc2 even though you dont have a table or view
######################################### ## Configuration for source id: floridaPerson ## Source configName: floridaPerson ######################################### subjectApi.source.floridaPerson.id = floridaPerson # this is a friendly name for the source subjectApi.source.floridaPerson.name = Florida person # type is not used all that much. Can have multiple types, comma separate. Can be person, group, application subjectApi.source.floridaPerson.types = person # the adapter class implements the interface: edu.internet2.middleware.subject.Source # adapter class must extend: edu.internet2.middleware.subject.provider.BaseSourceAdapter # edu.internet2.middleware.grouper.subj.GrouperJdbcSourceAdapter2 : if doing JDBC this should be used if possible. All subject data in one table/view. # edu.internet2.middleware.grouper.subj.GrouperJdbcSourceAdapter : oldest JDBC source. Put freeform queries in here # edu.internet2.middleware.grouper.subj.GrouperJndiSourceAdapter : used for LDAP subjectApi.source.floridaPerson.adapterClass = edu.internet2.middleware.subject.provider.JDBCSourceAdapter2 subjectApi.source.floridaPerson.param.jdbcConnectionProvider.value = edu.internet2.middleware.subject.provider.C3p0JdbcConnectionProvider subjectApi.source.floridaPerson.param.email.value = mail subjectApi.source.floridaPerson.param.maxPageSize.value = 100 subjectApi.source.floridaPerson.param.dbDriver.value = oracle.jdbc.driver.OracleDriver subjectApi.source.floridaPerson.param.dbUrl.value = jdbc:oracle:thin:@(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = orrcdbdv2-clstr.seo.int)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = dcom) ) ) subjectApi.source.floridaPerson.param.dbUser.value = pcdadmin subjectApi.source.floridaPerson.param.dbPwd.value = jyc7wmz2sbr6dw # maximum number of results from a search, generally no need to get more than 1000 subjectApi.source.floridaPerson.param.maxResults.value = 1000 # the table or view to query results from. Note, could prefix with a schema name subjectApi.source.floridaPerson.param.dbTableOrView.value = (select id, netId, name, email, description, lower(description) as search_description from ( select s.ARP_PAR_GLID || '@ufl.edu' AS id, s.ARP_PAR_GLID as netId, s.ARP_PAR_UF_EMAIL_AD as email, TRIM (s.ARP_PAR_FIRST_NM) || ' ' || CASE WHEN LENGTH (TRIM (s.ARP_PAR_MIDDLE_NM)) > 0 THEN TRIM (s.ARP_PAR_MIDDLE_NM) || ' ' END || CASE WHEN LENGTH (TRIM (s.ARP_PAR_LAST_NM)) > 0 THEN TRIM (s.ARP_PAR_LAST_NM) END || CASE WHEN LENGTH (TRIM (s.ARP_PAR_SUFFIX_NM)) > 0 THEN ' ' || TRIM (s.ARP_PAR_SUFFIX_NM) END AS name, TRIM (s.ARP_PAR_FIRST_NM) || ' ' || CASE WHEN LENGTH (TRIM (s.ARP_PAR_MIDDLE_NM)) > 0 THEN TRIM (s.ARP_PAR_MIDDLE_NM) || ' ' END || CASE WHEN LENGTH (TRIM (s.ARP_PAR_LAST_NM)) > 0 THEN TRIM (s.ARP_PAR_LAST_NM) END || CASE WHEN LENGTH (TRIM (s.ARP_PAR_SUFFIX_NM)) > 0 THEN ' ' || TRIM (s.ARP_PAR_SUFFIX_NM) END || ', ' || s.ARP_PAR_GLID || '@ufl.edu, ' || s.ARP_PAR_PRI_AFF_TYPE || ', ' || s.ARP_PAR_PRIMARY_DEPTID || ', ' || s.ARP_PAR_UF_EMAIL_AD AS description from ARP_PERSON_INFO s WHERE s.ARP_PAR_STATUS_FLG = 'A')) # the column name to get the subjectId from subjectApi.source.floridaPerson.param.subjectIdCol.value = id # the column name to get the name from subjectApi.source.floridaPerson.param.nameCol.value = name subjectApi.source.floridaPerson.param.descriptionCol.value = description # search col where general searches take place, lower case subjectApi.source.floridaPerson.param.lowerSearchCol.value = search_description # optional col if you want the search results sorted in the API (note, UI might override) subjectApi.source.floridaPerson.param.defaultSortCol.value = description # you can count up from 0 to N of columns to search by identifier (which might also include by id) subjectApi.source.floridaPerson.param.subjectIdentifierCol0.value = netId # now you can count up from 0 to N of attributes for various cols. The name is how to reference in subject.getAttribute() subjectApi.source.floridaPerson.param.subjectAttributeCol0.value = netId # you can count up from 0 to N of attributes for various cols. The name is how to reference in subject.getAttribute() subjectApi.source.floridaPerson.param.subjectAttributeName0.value = netId # now you can count up from 0 to N of attributes for various cols. The name is how to reference in subject.getAttribute() subjectApi.source.floridaPerson.param.subjectAttributeCol1.value = email # you can count up from 0 to N of attributes for various cols. The name is how to reference in subject.getAttribute() subjectApi.source.floridaPerson.param.subjectAttributeName1.value = email # email attribute name subjectApi.source.floridaPerson.param.emailAttributeName.value = email # the 1st sort attribute for lists on screen that are derived from member table (e.g. search for member in group) # you can have up to 5 sort attributes subjectApi.source.floridaPerson.param.sortAttribute0.value = description # the 1st search attribute for lists on screen that are derived from member table (e.g. search for member in group) # you can have up to 5 search attributes subjectApi.source.floridaPerson.param.searchAttribute0.value = description_lower
Then the subject source works
SUCCESS: Found subject by id in 22ms: 'mchyzer@ufl.edu' with SubjectFinder.findByIdAndSource("mchyzer@ufl.edu", "floridaPerson", false) SUCCESS: Subject id in returned subject matches the subject id searched for: 'mchyzer@ufl.edu' SUCCESS: Found subject by identifier in 3ms: 'mchyzer' with SubjectFinder.findByIdentifierAndSource("mchyzer", "floridaPerson", false) SUCCESS: Found 1 subjects by search string in 15ms: 'chr hyz' with SubjectFinder.findAll("chr hyz", "floridaPerson") SUCCESS: Found 1 subjects by paged search string in 8ms: 'chr hyz' with SubjectFinder.findPage("chr hyz", "floridaPerson") ######## SUBJECT ATTRIBUTES ######## Subject id: 'mchyzer@ufl.edu' with subject.getId() - the subject id should be an unchanging opaque identifier - the subject id is stored in the grouper_members table Subject name: 'Chris Michael Hyzer' with subject.getName() - the subject name is generally first last Subject description: 'Chris Michael Hyzer, mchyzer@ufl.edu, S, ISC, mchyzer@isc.upenn.edu' with subject.getDescription() - the subject description can have more info such as the id, name, dept, etc Subject type: 'person' with subject.getTypeName() - the subject type is not really used Subject attribute 'email' has 1 value: 'mchyzer@isc.upenn.edu' - with subject.getAttributeValue("email") Subject attribute 'netid' has 1 value: 'mchyzer' - with subject.getAttributeValue("netid") SUCCESS: The emailAttributeName is configured to be: 'email' SUCCESS: The email address 'mchyzer@isc.upenn.edu' was found and has a valid format ######## SUBJECT IN UI ######## Short link with icon: Chris Michael Hyzer - This is configured in grouper.text.en.us.base.properties with guiSubjectShortLink - Also configured in grouper-ui.properties with grouperUi.screenLabel2.sourceId.X - By default this is the name of the subject with a tooltip for description Long label with icon: Chris Michael Hyzer, mchyzer@ufl.edu, S, ISC, mchyzer@isc.upenn.edu - This is not used in the new UI - It is configured in grouper-ui.properties with grouperUi.subjectImg.screenEl. - By default this is the description of the subject ######## SUBJECT IN WS ######## Look in grouper-ws.properties to see how the WS uses subjects. This is the default configuation: # subject attribute names to send back when a WsSubjectResult is sent, comma separated # e.g. name, netid # default is none ws.subject.result.attribute.names = # subject result attribute names when extended data is requested (comma separated) # default is name, description # note, these will be in addition to ws.subject.result.attribute.names ws.subject.result.detail.attribute.names = ######## SOURCE CONFIGURATION ######## Adapter class: 'edu.internet2.middleware.subject.provider.JDBCSourceAdapter2' - configured in subject.properties: subjectApi.source.floridaPerson.adapterClass SUCCESS: Found adapter class SUCCESS: Instantiated adapter class Source id: 'floridaPerson' - configured in subject.properties: subjectApi.source.floridaPerson.id Source name: 'Florida person' - configured in subject.properties: subjectApi.source.floridaPerson.name Source types: 'person' - configured in subject.properties: subjectApi.source.floridaPerson.types Source param name: 'searchAttribute0' has value: 'description_lower' - configured in subject.properties: subjectApi.source.floridaPerson.param.searchAttribute0.value Source param name: 'dbUser' has value: 'pcdadmin' - configured in subject.properties: subjectApi.source.floridaPerson.param.dbUser.value Source param name: 'subjectAttributeCol1' has value: 'email' - configured in subject.properties: subjectApi.source.floridaPerson.param.subjectAttributeCol1.value Source param name: 'nameCol' has value: 'name' - configured in subject.properties: subjectApi.source.floridaPerson.param.nameCol.value Source param name: 'subjectAttributeCol0' has value: 'netId' - configured in subject.properties: subjectApi.source.floridaPerson.param.subjectAttributeCol0.value Source param name: 'subjectAttributeName1' has value: 'email' - configured in subject.properties: subjectApi.source.floridaPerson.param.subjectAttributeName1.value Source param name: 'subjectAttributeName0' has value: 'netId' - configured in subject.properties: subjectApi.source.floridaPerson.param.subjectAttributeName0.value Source param name: 'subjectIdCol' has value: 'id' - configured in subject.properties: subjectApi.source.floridaPerson.param.subjectIdCol.value Source param name: 'dbUrl' has value: 'jdbc:oracle:thin:@(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = orrcdbdv2-clstr.seo.int)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = dcom) ) )' - configured in subject.properties: subjectApi.source.floridaPerson.param.dbUrl.value Source param name: 'email' has value: 'mail' - configured in subject.properties: subjectApi.source.floridaPerson.param.email.value Source param name: 'subjectIdentifierCol0' has value: 'netId' - configured in subject.properties: subjectApi.source.floridaPerson.param.subjectIdentifierCol0.value Source param name: 'maxResults' has value: '1000' - configured in subject.properties: subjectApi.source.floridaPerson.param.maxResults.value Source param name: 'maxPageSize' has value: '100' - configured in subject.properties: subjectApi.source.floridaPerson.param.maxPageSize.value Source param name: 'dbPwd' has value: '*******' - configured in subject.properties: subjectApi.source.floridaPerson.param.dbPwd.value Source param name: 'lowerSearchCol' has value: 'search_description' - configured in subject.properties: subjectApi.source.floridaPerson.param.lowerSearchCol.value Source param name: 'emailAttributeName' has value: 'email' - configured in subject.properties: subjectApi.source.floridaPerson.param.emailAttributeName.value Source param name: 'dbTableOrView' has value: '(select id, netId, name, email, description, lower(description) as search_description from ( select s.ARP_PAR_GLID || '@ufl.edu' AS id, s.ARP_PAR_GLID as netId, s.ARP_PAR_UF_EMAIL_AD as email, TRIM (s.ARP_PAR_FIRST_NM) || ' ' || CASE WHEN LENGTH (TRIM (s.ARP_PAR_MIDDLE_NM)) > 0 THEN TRIM (s.ARP_PAR_MIDDLE_NM) || ' ' END || CASE WHEN LENGTH (TRIM (s.ARP_PAR_LAST_NM)) > 0 THEN TRIM (s.ARP_PAR_LAST_NM) END || CASE WHEN LENGTH (TRIM (s.ARP_PAR_SUFFIX_NM)) > 0 THEN ' ' || TRIM (s.ARP_PAR_SUFFIX_NM) END AS name, TRIM (s.ARP_PAR_FIRST_NM) || ' ' || CASE WHEN LENGTH (TRIM (s.ARP_PAR_MIDDLE_NM)) > 0 THEN TRIM (s.ARP_PAR_MIDDLE_NM) || ' ' END || CASE WHEN LENGTH (TRIM (s.ARP_PAR_LAST_NM)) > 0 THEN TRIM (s.ARP_PAR_LAST_NM) END || CASE WHEN LENGTH (TRIM (s.ARP_PAR_SUFFIX_NM)) > 0 THEN ' ' || TRIM (s.ARP_PAR_SUFFIX_NM) END || ', ' || s.ARP_PAR_GLID || '@ufl.edu, ' || s.ARP_PAR_PRI_AFF_TYPE || ', ' || s.ARP_PAR_PRIMARY_DEPTID || ', ' || s.ARP_PAR_UF_EMAIL_AD AS description from ARP_PERSON_INFO s WHERE s.ARP_PAR_STATUS_FLG = 'A'))' - configured in subject.properties: subjectApi.source.floridaPerson.param.dbTableOrView.value Source param name: 'dbDriver' has value: 'oracle.jdbc.driver.OracleDriver' - configured in subject.properties: subjectApi.source.floridaPerson.param.dbDriver.value Source param name: 'sortAttribute0' has value: 'description' - configured in subject.properties: subjectApi.source.floridaPerson.param.sortAttribute0.value Source param name: 'jdbcConnectionProvider' has value: 'edu.internet2.middleware.subject.provider.C3p0JdbcConnectionProvider' - configured in subject.properties: subjectApi.source.floridaPerson.param.jdbcConnectionProvider.value Source param name: 'descriptionCol' has value: 'description' - configured in subject.properties: subjectApi.source.floridaPerson.param.descriptionCol.value Source param name: 'defaultSortCol' has value: 'description' - configured in subject.properties: subjectApi.source.floridaPerson.param.defaultSortCol.value No internal attributes configured No attributes configured ######## SUBJECT SEARCH RESULTS ######## Subject 0: id: mchyzer@ufl.edu, name: Chris Michael Hyzer - description: Chris Michael Hyzer, mchyzer@ufl.edu, S, ISC, mchyzer@isc.upenn.edu ######## SUBJECT PAGE RESULTS ######## Subject 0: id: mchyzer@ufl.edu, name: Chris Michael Hyzer - description: Chris Michael Hyzer, mchyzer@ufl.edu, S, ISC, mchyzer@isc.upenn.edu