Issue #1412 Check file last modified times each time role data is requested

Change-Id: Ieae84ad3106e3aa0cf4d253a10c27e8c9c60ecaa

Former-commit-id: b1ce19e41d [formerly 74d5a70c30] [formerly 037dabb683 [formerly b7e577237df9e157fdb218af48c41f6209ff2bfb]]
Former-commit-id: 037dabb683
Former-commit-id: 6468029207
This commit is contained in:
Dustin Johnson 2013-01-17 12:46:27 -06:00
parent aacdfed4a3
commit fce3f8bec9
12 changed files with 343 additions and 35 deletions

View file

@ -29,6 +29,8 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.xml.bind.JAXBException;
import com.raytheon.uf.common.localization.FileLocker.Type;
import com.raytheon.uf.common.localization.ILocalizationAdapter.ListResponse;
import com.raytheon.uf.common.localization.LocalizationContext.LocalizationLevel;
@ -80,6 +82,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
* This was added as part of an effort to improve
* localization performance but caused updated
* files on the server not to be retrieved.
* Jan 17, 2013 1412 djohnson Add jaxbMarshal.
* </pre>
*
* @author njensen
@ -635,6 +638,25 @@ public final class LocalizationFile implements Comparable<LocalizationFile> {
return null;
}
/**
* Marshal the specified object into this file.
*
* @param obj
* the object to marshal
*
* @param jaxbManager
* the jaxbManager
*/
public void jaxbMarshal(Object obj, JAXBManager jaxbManager) throws LocalizationException{
try {
String xml = jaxbManager.marshalToXml(obj);
write(xml.getBytes());
} catch (JAXBException e) {
throw new LocalizationException(
"Unable to marshal the object to the file.", e);
}
}
@Override
public String toString() {
return context + IPathManager.SEPARATOR + path;

View file

@ -10,7 +10,8 @@ Require-Bundle: com.raytheon.uf.common.serialization;bundle-version="1.12.2",
com.raytheon.uf.common.auth;bundle-version="1.12.1174",
com.raytheon.uf.common.status;bundle-version="1.12.1174",
com.raytheon.uf.common.localization;bundle-version="1.12.1174",
com.raytheon.uf.common.serialization.comm;bundle-version="1.12.1174"
com.raytheon.uf.common.serialization.comm;bundle-version="1.12.1174",
org.apache.commons.lang;bundle-version="2.3.0"
Export-Package: com.raytheon.uf.common.plugin.nwsauth,
com.raytheon.uf.common.plugin.nwsauth.exception,
com.raytheon.uf.common.plugin.nwsauth.user,

View file

@ -302,4 +302,21 @@ public class NwsRoleData implements ISerializableObject {
return false;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Application:").append(this.getApplication()).append("\n\n");
sb.append("Users:\n").append(this.getUserList()).append("\n\n");
sb.append("Permissions:\n").append(this.getPermissionList())
.append("\n\n");
sb.append("Roles:\n").append(this.getRoleList()).append("\n\n");
return sb.toString();
}
}

View file

@ -94,4 +94,16 @@ public class PermissionXML implements ISerializableObject {
public void setDescription(String description) {
this.description = (description == null) ? null : description.trim();
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("id:").append(this.getId());
sb.append("\ndescription:").append(this.getDescription());
return sb.toString();
}
}

View file

@ -117,4 +117,19 @@ public class RoleXML implements ISerializableObject {
public void addPermission(String permission) {
this.permissionList.add(permission);
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("roleId:").append(this.getRoleId());
sb.append("\nroleDescription:").append(this.getRoleDescription());
sb.append("\npermissionList:").append(this.getPermissionList());
return sb.toString();
}
}

View file

@ -28,6 +28,9 @@ import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElements;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import com.raytheon.uf.common.auth.user.IAuthenticationData;
import com.raytheon.uf.common.auth.user.IUser;
import com.raytheon.uf.common.auth.user.IUserId;
@ -66,6 +69,17 @@ public class UserXML implements IUser, ISerializableObject {
@XmlElements({ @XmlElement(name = "userRole", type = String.class) })
private List<String> roleList = new ArrayList<String>();
public UserXML() {
}
/**
* @param userId
*/
public UserXML(String userId) {
setUserId(userId);
}
/**
* @return the userId
*/
@ -129,6 +143,30 @@ public class UserXML implements IUser, ISerializableObject {
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (obj instanceof UserXML) {
UserXML that = (UserXML) obj;
EqualsBuilder builder = new EqualsBuilder();
builder.append(this.getUserId(), that.getUserId());
return builder.isEquals();
}
return super.equals(obj);
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return new HashCodeBuilder().append(this.getUserId()).toHashCode();
}
/*
* (non-Javadoc)
*
@ -136,17 +174,10 @@ public class UserXML implements IUser, ISerializableObject {
*/
@Override
public String toString() {
final String nl = "\n";
StringBuilder sb = new StringBuilder();
sb.append(this.getUserId()).append(nl);
for (String role : this.roleList) {
sb.append(" ").append(role).append(nl);
}
for (String perm : permissionList) {
sb.append(" ").append(perm).append(nl);
}
sb.append("userId:").append(this.getUserId());
sb.append("\nroles:").append(this.getRoleList());
sb.append("\npermissions:").append(this.getPermissionList());
return sb.toString();
}

View file

@ -11,7 +11,8 @@ Require-Bundle: com.raytheon.uf.edex.auth;bundle-version="1.12.2",
com.raytheon.uf.common.status;bundle-version="1.12.1174",
com.raytheon.uf.common.localization,
com.raytheon.uf.common.serialization.comm;bundle-version="1.12.1174",
com.raytheon.uf.common.useradmin;bundle-version="1.0.0"
com.raytheon.uf.common.useradmin;bundle-version="1.0.0",
com.raytheon.uf.common.time;bundle-version="1.12.1174"
Import-Package: com.raytheon.uf.common.localization,
com.raytheon.uf.common.serialization,
com.raytheon.uf.common.status,

View file

@ -19,9 +19,11 @@
**/
package com.raytheon.uf.edex.plugin.nwsauth;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
import javax.xml.bind.JAXBException;
@ -40,6 +42,7 @@ import com.raytheon.uf.common.serialization.JAXBManager;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.time.util.TimeUtil;
/**
* Uses localization data to determine role/permissions. Intentionally
@ -51,7 +54,9 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jan 09, 2013 1412 djohnson Moved file writing from viz plugin to server-side.
* Jan 09, 2013 1412 djohnson Moved file writing from viz plugin to server-side.
* Jan 17, 2013 1412 djohnson Check files for having been modified each time data is requested,
* in case they were written by another member of the cluster.
*
* </pre>
*
@ -69,14 +74,22 @@ class FileManager {
private final String ROLE_DIR = "roles";
private final Map<String, NwsRoleData> roleDataMap = new HashMap<String, NwsRoleData>();
private final AtomicLong lastReadTime = new AtomicLong(-1L);
/**
* Application name -> Role Data.
*/
private final ConcurrentMap<String, NwsRoleData> roleDataMap = new ConcurrentHashMap<String, NwsRoleData>();
/**
* Application name -> LocalizationFile map.
*/
private final Map<String, LocalizationFile> roleFileMap = new HashMap<String, LocalizationFile>();
private final ConcurrentMap<String, LocalizationFile> roleFileMap = new ConcurrentHashMap<String, LocalizationFile>();
private FileManager() {
/**
* Package-level visibility so tests can create new instances.
*/
FileManager() {
readXML();
}
@ -117,31 +130,54 @@ class FileManager {
private void readXML() {
try {
getJaxbManager();
IPathManager pm = PathManagerFactory.getPathManager();
LocalizationContext[] contexts = new LocalizationContext[2];
contexts[0] = pm.getContext(LocalizationType.COMMON_STATIC,
LocalizationLevel.BASE);
contexts[1] = pm.getContext(LocalizationType.COMMON_STATIC,
LocalizationLevel.SITE);
LocalizationFile[] roleFiles = pm.listFiles(contexts, ROLE_DIR,
new String[] { ".xml" }, false, true);
LocalizationFile[] roleFiles = getUserRoleLocalizationFiles();
boolean needToReadFiles = false;
for (LocalizationFile lf : roleFiles) {
NwsRoleData roleData = lf.jaxbUnmarshal(NwsRoleData.class,
getJaxbManager());
final long fileLastModified = lf.getFile().lastModified();
final long lastTimeFilesWereRead = lastReadTime.get();
if (roleData != null) {
this.roleDataMap.put(roleData.getApplication(), roleData);
this.roleFileMap.put(roleData.getApplication(), lf);
if (fileLastModified > lastTimeFilesWereRead) {
needToReadFiles = true;
break;
}
}
if (needToReadFiles) {
for (LocalizationFile lf : roleFiles) {
final long fileLastModified = lf.getFile().lastModified();
final long lastTimeFilesWereRead = lastReadTime.get();
if (fileLastModified < lastTimeFilesWereRead) {
continue;
}
NwsRoleData roleData = lf.jaxbUnmarshal(NwsRoleData.class,
getJaxbManager());
if (roleData != null) {
final String application = roleData.getApplication();
this.roleDataMap.put(application, roleData);
this.roleFileMap.put(application, lf);
}
}
}
lastReadTime.set(TimeUtil.currentTimeMillis());
} catch (Exception e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e);
}
}
private LocalizationFile[] getUserRoleLocalizationFiles() {
IPathManager pm = PathManagerFactory.getPathManager();
LocalizationContext[] contexts = new LocalizationContext[2];
contexts[0] = pm.getContext(LocalizationType.COMMON_STATIC,
LocalizationLevel.BASE);
contexts[1] = pm.getContext(LocalizationType.COMMON_STATIC,
LocalizationLevel.SITE);
LocalizationFile[] roleFiles = pm.listFiles(contexts, ROLE_DIR,
new String[] { ".xml" }, false, true);
return roleFiles;
}
private JAXBManager getJaxbManager() throws JAXBException {
if (jaxbManager == null) {
jaxbManager = new JAXBManager(NwsRoleData.class,
@ -154,13 +190,15 @@ class FileManager {
* @return
*/
public Map<String, NwsRoleData> getRoleDataMap() {
readXML();
return roleDataMap;
}
/**
* @param roleDataWithChanges
*/
public void writeApplicationRoleData(Map<String, NwsRoleData> roleDataWithChanges) {
public void writeApplicationRoleData(
Map<String, NwsRoleData> roleDataWithChanges) {
for (Entry<String, NwsRoleData> entry : roleDataWithChanges.entrySet()) {
final String application = entry.getKey();
roleDataMap.put(application, entry.getValue());

View file

@ -67,5 +67,6 @@
<classpathentry combineaccessrules="false" kind="src" path="/com.raytheon.uf.common.stats"/>
<classpathentry combineaccessrules="false" kind="src" path="/com.raytheon.uf.edex.stats"/>
<classpathentry combineaccessrules="false" kind="src" path="/com.raytheon.uf.viz.plugin.nwsauth"/>
<classpathentry combineaccessrules="false" kind="src" path="/com.raytheon.uf.edex.plugin.nwsauth"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View file

@ -165,7 +165,7 @@ public class TestPathManager extends PathManager {
try {
if (baselinedVersion.exists()) {
if (baselinedVersion.isDirectory()) {
savedFile.mkdirs();
FileUtil.copyDirectory(baselinedVersion, savedFile);
} else {
FileUtil.copyFile(baselinedVersion, savedFile);
}

View file

@ -0,0 +1,156 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.edex.plugin.nwsauth;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Map;
import javax.xml.bind.JAXBException;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import com.raytheon.uf.common.localization.IPathManager;
import com.raytheon.uf.common.localization.LocalizationContext;
import com.raytheon.uf.common.localization.LocalizationContext.LocalizationLevel;
import com.raytheon.uf.common.localization.LocalizationContext.LocalizationType;
import com.raytheon.uf.common.localization.LocalizationFile;
import com.raytheon.uf.common.localization.PathManagerFactory;
import com.raytheon.uf.common.localization.PathManagerFactoryTest;
import com.raytheon.uf.common.localization.exception.LocalizationException;
import com.raytheon.uf.common.plugin.nwsauth.xml.NwsRoleData;
import com.raytheon.uf.common.plugin.nwsauth.xml.UserXML;
import com.raytheon.uf.common.serialization.JAXBManager;
import com.raytheon.uf.common.time.util.TimeUtil;
import com.raytheon.uf.common.time.util.TimeUtilTest;
/**
* Test {@link FileManager}.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jan 17, 2013 1412 djohnson Initial creation
*
* </pre>
*
* @author djohnson
* @version 1.0
*/
public class FileManagerTest {
private static JAXBManager jaxbManager;
private final UserXML someUser = new UserXML("someUser");
private FileManager manager;
@BeforeClass
public static void classSetup() throws JAXBException {
jaxbManager = new JAXBManager(NwsRoleData.class);
}
@Before
public void setUp() {
TimeUtilTest.freezeTime();
PathManagerFactoryTest.initLocalization();
manager = new FileManager();
}
@After
public void tearDown() {
TimeUtilTest.resumeTime();
}
@Test
public void fileNewerOnDiskIsReadBeforeResponse()
throws LocalizationException {
addUserToUserAdminFile();
verifyUserIsFoundWhenRoleDataRetrieved();
}
@Test
public void fileOlderOnDiskIsNotReadBeforeResponse()
throws LocalizationException {
addUserToUserAdminFile();
setUserAdminFileModifiedTimeToOneSecondAgo();
verifyUserIsNotFoundWhenRoleDataRetrieved();
}
private void verifyUserIsFoundWhenRoleDataRetrieved() {
final Map<String, NwsRoleData> roleDataMap = manager.getRoleDataMap();
assertTrue(
"Did not find the user added to the role data map!",
roleDataMap.get("TestUserRoles").getUserList()
.contains(someUser));
}
/**
* @param someUser
*/
private void verifyUserIsNotFoundWhenRoleDataRetrieved() {
final Map<String, NwsRoleData> roleDataMap = manager.getRoleDataMap();
assertFalse(
"Should not have found the user added to the role data map!",
roleDataMap.get("TestUserRoles").getUserList()
.contains(someUser));
}
private void addUserToUserAdminFile() throws LocalizationException {
final LocalizationFile file = getTestUserAdminRolesLocalizationFile();
NwsRoleData roleData = file.jaxbUnmarshal(NwsRoleData.class,
jaxbManager);
roleData.getUserList().add(someUser);
file.jaxbMarshal(roleData, jaxbManager);
file.save();
// The file was written out 1 second after we last read it
file.getFile().setLastModified(
TimeUtil.currentTimeMillis() + TimeUtil.MILLIS_PER_SECOND);
}
private void setUserAdminFileModifiedTimeToOneSecondAgo() {
// The file was written out 1 second before we last read it
getTestUserAdminRolesLocalizationFile().getFile().setLastModified(
TimeUtil.currentTimeMillis() - TimeUtil.MILLIS_PER_SECOND);
}
private LocalizationFile getTestUserAdminRolesLocalizationFile() {
IPathManager pathManager = PathManagerFactory.getPathManager();
final LocalizationFile file = pathManager.getLocalizationFile(
new LocalizationContext(LocalizationType.COMMON_STATIC,
LocalizationLevel.SITE, "OAX"),
"roles/testUserAdminRoles.xml");
return file;
}
}

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<nwsRoleData xmlns:ns2="group">
<!-- AWIPS 2 User Admin Roles/Permissions file -->
<application>TestUserRoles</application>
<permission id="awips.user.admin">
<description>
This permission allows the user to access and edit AWIPS 2 User Administration
</description>
</permission>
<user userId="ALL">
<userPermission>awips.user.admin</userPermission>
</user>
</nwsRoleData>